diff options
-rw-r--r-- | lib/httpserver/HTTPRequest.cpp | 135 | ||||
-rw-r--r-- | lib/httpserver/HTTPRequest.h | 34 |
2 files changed, 140 insertions, 29 deletions
diff --git a/lib/httpserver/HTTPRequest.cpp b/lib/httpserver/HTTPRequest.cpp index 8ba44903..aa064363 100644 --- a/lib/httpserver/HTTPRequest.cpp +++ b/lib/httpserver/HTTPRequest.cpp @@ -15,6 +15,7 @@ #include <stdio.h> #include "HTTPRequest.h" +#include "HTTPResponse.h" #include "HTTPQueryDecoder.h" #include "autogen_HTTPException.h" #include "IOStream.h" @@ -44,7 +45,9 @@ HTTPRequest::HTTPRequest() mHTTPVersion(0), mContentLength(-1), mpCookies(0), - mClientKeepAliveRequested(false) + mClientKeepAliveRequested(false), + mExpectContinue(false), + mpStreamToReadFrom(NULL) { } @@ -61,11 +64,13 @@ HTTPRequest::HTTPRequest() HTTPRequest::HTTPRequest(enum Method method, const std::string& rURI) : mMethod(method), mRequestURI(rURI), - mHostPort(80), // default if not specified + mHostPort(80), // default if not specified mHTTPVersion(HTTPVersion_1_1), mContentLength(-1), mpCookies(0), - mClientKeepAliveRequested(false) + mClientKeepAliveRequested(false), + mExpectContinue(false), + mpStreamToReadFrom(NULL) { } @@ -120,30 +125,36 @@ bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout) // Check the method unsigned int p = 0; // current position in string - if(::strncmp(requestLine.c_str(), "GET ", 4) == 0) - { - p = 3; - mMethod = Method_GET; - } - else if(::strncmp(requestLine.c_str(), "HEAD ", 5) == 0) - { - p = 4; - mMethod = Method_HEAD; - } - else if(::strncmp(requestLine.c_str(), "POST ", 5) == 0) + p = requestLine.find(' '); // end of first word + + if (p == std::string::npos) { - p = 4; - mMethod = Method_POST; + // No terminating space, looks bad + p = requestLine.size(); } else { - p = requestLine.find(' '); - if(p == std::string::npos) + std::string method = requestLine.substr(0, p); + if (method == "GET") { - // No terminating space, looks bad - p = requestLine.size(); + mMethod = Method_GET; + } + else if (method == "HEAD") + { + mMethod = Method_HEAD; + } + else if (method == "POST") + { + mMethod = Method_POST; + } + else if (method == "PUT") + { + mMethod = Method_PUT; + } + else + { + mMethod = Method_UNKNOWN; } - mMethod = Method_UNKNOWN; } // Skip spaces to find URI @@ -263,6 +274,15 @@ bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout) // Now parse the headers ParseHeaders(rGetLine, Timeout); + std::string expected; + if (GetHeader("Expect", &expected)) + { + if (expected == "100-continue") + { + mExpectContinue = true; + } + } + // Parse form data? if(mMethod == Method_POST && mContentLength >= 0) { @@ -305,10 +325,42 @@ bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout) // Finish off decoder.Finish(); } + else if (mContentLength > 0) + { + IOStream::pos_type bytesToCopy = rGetLine.GetSizeOfBufferedData(); + if (bytesToCopy > mContentLength) + { + bytesToCopy = mContentLength; + } + Write(rGetLine.GetBufferedData(), bytesToCopy); + SetForReading(); + mpStreamToReadFrom = &(rGetLine.GetUnderlyingStream()); + } return true; } +void HTTPRequest::ReadContent(IOStream& rStreamToWriteTo) +{ + Seek(0, SeekType_Absolute); + + CopyStreamTo(rStreamToWriteTo); + IOStream::pos_type bytesCopied = GetSize(); + + while (bytesCopied < mContentLength) + { + char buffer[1024]; + IOStream::pos_type bytesToCopy = sizeof(buffer); + if (bytesToCopy > mContentLength - bytesCopied) + { + bytesToCopy = mContentLength - bytesCopied; + } + bytesToCopy = mpStreamToReadFrom->Read(buffer, bytesToCopy); + rStreamToWriteTo.Write(buffer, bytesToCopy); + bytesCopied += bytesToCopy; + } +} + // -------------------------------------------------------------------------- // // Function @@ -317,7 +369,7 @@ bool HTTPRequest::Receive(IOStreamGetLine &rGetLine, int Timeout) // Created: 03/01/09 // // -------------------------------------------------------------------------- -bool HTTPRequest::Send(IOStream &rStream, int Timeout) +bool HTTPRequest::Send(IOStream &rStream, int Timeout, bool ExpectContinue) { switch (mMethod) { @@ -331,6 +383,8 @@ bool HTTPRequest::Send(IOStream &rStream, int Timeout) rStream.Write("HEAD"); break; case Method_POST: rStream.Write("POST"); break; + case Method_PUT: + rStream.Write("PUT"); break; } rStream.Write(" "); @@ -391,6 +445,11 @@ bool HTTPRequest::Send(IOStream &rStream, int Timeout) { oss << i->first << ": " << i->second << "\n"; } + + if (ExpectContinue) + { + oss << "Expect: 100-continue\n"; + } rStream.Write(oss.str().c_str()); rStream.Write("\n"); @@ -398,6 +457,31 @@ bool HTTPRequest::Send(IOStream &rStream, int Timeout) return true; } +void HTTPRequest::SendWithStream(IOStream &rStreamToSendTo, int Timeout, + IOStream* pStreamToSend, HTTPResponse& rResponse) +{ + IOStream::pos_type size = pStreamToSend->BytesLeftToRead(); + + if (size != IOStream::SizeOfStreamUnknown) + { + mContentLength = size; + } + + Send(rStreamToSendTo, Timeout, true); + + rResponse.Receive(rStreamToSendTo, Timeout); + if (rResponse.GetResponseCode() != 100) + { + // bad response, abort now + return; + } + + pStreamToSend->CopyStreamTo(rStreamToSendTo, Timeout); + + // receive the final response + rResponse.Receive(rStreamToSendTo, Timeout); +} + // -------------------------------------------------------------------------- // // Function @@ -509,7 +593,12 @@ void HTTPRequest::ParseHeaders(IOStreamGetLine &rGetLine, int Timeout) } // else don't understand, just assume default for protocol version } - // else ignore it + else + { + std::string name = header.substr(0, p); + mExtraHeaders.push_back(Header(name, + h + dataStart)); + } // Unset have header flag, as it's now been processed haveHeader = false; diff --git a/lib/httpserver/HTTPRequest.h b/lib/httpserver/HTTPRequest.h index dc81d593..58874092 100644 --- a/lib/httpserver/HTTPRequest.h +++ b/lib/httpserver/HTTPRequest.h @@ -13,6 +13,9 @@ #include <string> #include <map> +#include "CollectInBufferStream.h" + +class HTTPResponse; class IOStream; class IOStreamGetLine; @@ -24,7 +27,7 @@ class IOStreamGetLine; // Created: 26/3/04 // // -------------------------------------------------------------------------- -class HTTPRequest +class HTTPRequest : public CollectInBufferStream { public: enum Method @@ -33,7 +36,8 @@ public: Method_UNKNOWN = 0, Method_GET = 1, Method_HEAD = 2, - Method_POST = 3 + Method_POST = 3, + Method_PUT = 4 }; HTTPRequest(); @@ -56,7 +60,10 @@ public: }; bool Receive(IOStreamGetLine &rGetLine, int Timeout); - bool Send(IOStream &rStream, int Timeout); + bool Send(IOStream &rStream, int Timeout, bool ExpectContinue = false); + void SendWithStream(IOStream &rStreamToSendTo, int Timeout, + IOStream* pStreamToSend, HTTPResponse& rResponse); + void ReadContent(IOStream& rStreamToWriteTo); typedef std::map<std::string, std::string> CookieJar_t; @@ -88,7 +95,20 @@ public: const CookieJar_t *GetCookies() const {return mpCookies;} // WARNING: May return NULL bool GetCookie(const char *CookieName, std::string &rValueOut) const; const std::string &GetCookie(const char *CookieName) const; - + bool GetHeader(const std::string& rName, std::string* pValueOut) const + { + for (std::vector<Header>::const_iterator + i = mExtraHeaders.begin(); + i != mExtraHeaders.end(); i++) + { + if (i->first == rName) + { + *pValueOut = i->second; + return true; + } + } + return false; + } // -------------------------------------------------------------------------- // @@ -109,12 +129,12 @@ public: { mExtraHeaders.push_back(Header(rName, rValue)); } - + bool IsExpectingContinue() const { return mExpectContinue; } + private: void ParseHeaders(IOStreamGetLine &rGetLine, int Timeout); void ParseCookies(const std::string &rHeader, int DataStarts); -private: enum Method mMethod; std::string mRequestURI; std::string mHostName; @@ -127,6 +147,8 @@ private: CookieJar_t *mpCookies; bool mClientKeepAliveRequested; std::vector<Header> mExtraHeaders; + bool mExpectContinue; + IOStream* mpStreamToReadFrom; }; #endif // HTTPREQUEST__H |