diff --git a/ChangeLog b/ChangeLog index c9cf2b540..d616f74f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2010-02-20 Tatsuhiro Tsujikawa + + User-defined custom request headers specified by --header option + now override builtin headers if they have same name. + * src/HttpRequest.cc + * src/HttpRequest.h + * test/HttpRequestTest.cc + 2010-02-19 Tatsuhiro Tsujikawa Rewirtten util::isNumber() diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 7e9cc0514..27f273829 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -49,6 +49,7 @@ #include "AuthConfig.h" #include "a2functional.h" #include "TimeA2.h" +#include "array_fun.h" namespace aria2 { @@ -155,59 +156,63 @@ std::string HttpRequest::createRequest() requestLine += getQuery(); } requestLine += " HTTP/1.1\r\n"; - strappend(requestLine, "User-Agent: ", userAgent, "\r\n"); - - requestLine += "Accept: */*"; /* */ - for(std::deque::const_iterator i = _acceptTypes.begin(); - i != _acceptTypes.end(); ++i) { - strappend(requestLine, ",", (*i)); - } - requestLine += "\r\n"; + std::vector > builtinHds; + builtinHds.reserve(20); + builtinHds.push_back(std::make_pair("User-Agent:", userAgent)); + std::string acceptTypes = "*/*"; + for(std::deque::const_iterator i = _acceptTypes.begin(), + end = _acceptTypes.end(); i != end; ++i) { + strappend(acceptTypes, ",", (*i)); + } + builtinHds.push_back(std::make_pair("Accept:", acceptTypes)); if(_contentEncodingEnabled) { std::string acceptableEncodings; #ifdef HAVE_LIBZ acceptableEncodings += "deflate, gzip"; #endif // HAVE_LIBZ if(!acceptableEncodings.empty()) { - strappend(requestLine, "Accept-Encoding: ", acceptableEncodings, "\r\n"); + builtinHds.push_back + (std::make_pair("Accept-Encoding:", acceptableEncodings)); } } - - strappend(requestLine, "Host: ", getHostText(getURIHost(), getPort()), "\r\n"); + builtinHds.push_back + (std::make_pair("Host:", getHostText(getURIHost(), getPort()))); if(_noCache) { - requestLine += "Pragma: no-cache\r\n"; - requestLine += "Cache-Control: no-cache\r\n"; + builtinHds.push_back(std::make_pair("Pragma:", "no-cache")); + builtinHds.push_back(std::make_pair("Cache-Control:", "no-cache")); } if(!request->isKeepAliveEnabled() && !request->isPipeliningEnabled()) { - requestLine += "Connection: close\r\n"; + builtinHds.push_back(std::make_pair("Connection:", "close")); } if(!segment.isNull() && segment->getLength() > 0 && (request->isPipeliningEnabled() || getStartByte() > 0)) { - requestLine += "Range: bytes="; - requestLine += util::itos(getStartByte()); - requestLine += "-"; + std::string rangeHeader = "bytes="; + rangeHeader += util::itos(getStartByte()); + rangeHeader += "-"; if(request->isPipeliningEnabled()) { - requestLine += util::itos(getEndByte()); + rangeHeader += util::itos(getEndByte()); } - requestLine += "\r\n"; + builtinHds.push_back(std::make_pair("Range:", rangeHeader)); } if(!_proxyRequest.isNull()) { if(request->isKeepAliveEnabled() || request->isPipeliningEnabled()) { - requestLine += "Proxy-Connection: Keep-Alive\r\n"; + builtinHds.push_back(std::make_pair("Proxy-Connection:", "Keep-Alive")); } else { - requestLine += "Proxy-Connection: close\r\n"; + builtinHds.push_back(std::make_pair("Proxy-Connection:", "close")); } } if(!_proxyRequest.isNull() && !_proxyRequest->getUsername().empty()) { - requestLine += getProxyAuthString(); + builtinHds.push_back(getProxyAuthString()); } if(!_authConfig.isNull()) { - strappend(requestLine, "Authorization: Basic ", - Base64::encode(_authConfig->getAuthText()), "\r\n"); + builtinHds.push_back + (std::make_pair("Authorization:", + strconcat("Basic ", + Base64::encode(_authConfig->getAuthText())))); } if(getPreviousURI().size()) { - strappend(requestLine, "Referer: ", getPreviousURI(), "\r\n"); + builtinHds.push_back(std::make_pair("Referer:", getPreviousURI())); } if(!_cookieStorage.isNull()) { std::string cookiesValue; @@ -217,21 +222,33 @@ std::string HttpRequest::createRequest() Time().getTime(), getProtocol() == Request::PROTO_HTTPS ? true : false); - for(std::deque::const_iterator itr = cookies.begin(); - itr != cookies.end(); ++itr) { + for(std::deque::const_iterator itr = cookies.begin(), + end = cookies.end(); itr != end; ++itr) { strappend(cookiesValue, (*itr).toString(), ";"); } if(!cookiesValue.empty()) { - strappend(requestLine, "Cookie: ", cookiesValue, "\r\n"); + builtinHds.push_back(std::make_pair("Cookie:", cookiesValue)); + } + } + for(std::vector >::iterator i = + builtinHds.begin(); i != builtinHds.end(); ++i) { + std::vector::const_iterator j = _headers.begin(); + std::vector::const_iterator jend = _headers.end(); + for(; j != jend; ++j) { + if(util::startsWith(*j, (*i).first)) { + break; + } + } + if(j == jend) { + strappend(requestLine, (*i).first, " ", (*i).second, A2STR::CRLF); } } // append additional headers given by user. - for(std::deque::const_iterator i = _headers.begin(); - i != _headers.end(); ++i) { - strappend(requestLine, (*i), "\r\n"); + for(std::vector::const_iterator i = _headers.begin(), + end = _headers.end(); i != end; ++i) { + strappend(requestLine, (*i), A2STR::CRLF); } - - requestLine += "\r\n"; + requestLine += A2STR::CRLF; return requestLine; } @@ -252,19 +269,21 @@ std::string HttpRequest::createProxyRequest() const // requestLine += "Proxy-Connection: close\r\n"; // } if(!_proxyRequest->getUsername().empty()) { - requestLine += getProxyAuthString(); + std::pair auth = getProxyAuthString(); + strappend(requestLine, auth.first, " ", auth.second, A2STR::CRLF); } - requestLine += "\r\n"; + requestLine += A2STR::CRLF; return requestLine; } -std::string HttpRequest::getProxyAuthString() const +std::pair HttpRequest::getProxyAuthString() const { - return strconcat("Proxy-Authorization: Basic ", - Base64::encode(strconcat(_proxyRequest->getUsername(), - ":", - _proxyRequest->getPassword())), - "\r\n"); + return std::make_pair + ("Proxy-Authorization:", + strconcat("Basic ", + Base64::encode(strconcat(_proxyRequest->getUsername(), + ":", + _proxyRequest->getPassword())))); } void HttpRequest::enableContentEncoding() diff --git a/src/HttpRequest.h b/src/HttpRequest.h index 2ba46a3fd..56e9d245c 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "SharedHandle.h" #include "Request.h" @@ -69,7 +70,7 @@ private: std::string userAgent; - std::deque _headers; + std::vector _headers; std::deque _acceptTypes; @@ -85,7 +86,7 @@ private: bool _noCache; - std::string getProxyAuthString() const; + std::pair getProxyAuthString() const; public: HttpRequest(); diff --git a/test/HttpRequestTest.cc b/test/HttpRequestTest.cc index 1e6001720..b03e410ce 100644 --- a/test/HttpRequestTest.cc +++ b/test/HttpRequestTest.cc @@ -663,16 +663,16 @@ void HttpRequestTest::testAddHeader() httpRequest.setRequest(request); httpRequest.setAuthConfigFactory(_authConfigFactory, _option.get()); httpRequest.addHeader("X-ARIA2: v0.13\nX-ARIA2-DISTRIBUTE: enabled\n"); - + httpRequest.addHeader("Accept: text/html"); std::string expectedText = "GET /archives/aria2-1.0.0.tar.bz2 HTTP/1.1\r\n" "User-Agent: aria2\r\n" - "Accept: */*\r\n" "Host: localhost\r\n" "Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n" "Connection: close\r\n" "X-ARIA2: v0.13\r\n" "X-ARIA2-DISTRIBUTE: enabled\r\n" + "Accept: text/html\r\n" "\r\n"; CPPUNIT_ASSERT_EQUAL(expectedText, httpRequest.createRequest());