[Box Backup-commit] COMMIT r2438 - box/trunk/lib/httpserver
boxbackup-dev@boxbackup.org
boxbackup-dev@boxbackup.org
Mon, 5 Jan 2009 00:48:01 +0000 (GMT)
Author: chris
Date: 2009-01-05 00:48:01 +0000 (Mon, 05 Jan 2009)
New Revision: 2438
Modified:
box/trunk/lib/httpserver/HTTPRequest.cpp
box/trunk/lib/httpserver/HTTPRequest.h
Log:
Don't read the whole uploaded body in HTTPRequest::Receive, as the
client may be expecting a 100 Continue header (or other response) before
sending it, and only the HTTPServer should send that for us.
Keep track of the stream that we're reading from, in case there's a body
to read later.
Simplify parsing of HTTP method, and add support for PUT requests.
Add support for parsing Expect headers and storing and retrieving any
unrecognised headers.
Add support for sending a streaming upload from an IOStream with an HTTP
request as the body (e.g. for PUT requests).
Modified: box/trunk/lib/httpserver/HTTPRequest.cpp
===================================================================
--- box/trunk/lib/httpserver/HTTPRequest.cpp 2009-01-05 00:47:23 UTC (rev 2437)
+++ box/trunk/lib/httpserver/HTTPRequest.cpp 2009-01-05 00:48:01 UTC (rev 2438)
@@ -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 @@
mHTTPVersion(0),
mContentLength(-1),
mpCookies(0),
- mClientKeepAliveRequested(false)
+ mClientKeepAliveRequested(false),
+ mExpectContinue(false),
+ mpStreamToReadFrom(NULL)
{
}
@@ -61,11 +64,13 @@
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 @@
// Check the method
unsigned int p = 0; // current position in string
- if(::strncmp(requestLine.c_str(), "GET ", 4) == 0)
+ p = requestLine.find(' '); // end of first word
+
+ if (p == std::string::npos)
{
- p = 3;
- mMethod = Method_GET;
+ // No terminating space, looks bad
+ p = requestLine.size();
}
- else if(::strncmp(requestLine.c_str(), "HEAD ", 5) == 0)
- {
- p = 4;
- mMethod = Method_HEAD;
- }
- else if(::strncmp(requestLine.c_str(), "POST ", 5) == 0)
- {
- p = 4;
- mMethod = Method_POST;
- }
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;
}
- mMethod = Method_UNKNOWN;
+ 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;
+ }
}
// Skip spaces to find URI
@@ -263,6 +274,15 @@
// 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 @@
// 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 @@
// 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 @@
rStream.Write("HEAD"); break;
case Method_POST:
rStream.Write("POST"); break;
+ case Method_PUT:
+ rStream.Write("PUT"); break;
}
rStream.Write(" ");
@@ -391,6 +445,11 @@
{
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 @@
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 @@
}
// 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;
Modified: box/trunk/lib/httpserver/HTTPRequest.h
===================================================================
--- box/trunk/lib/httpserver/HTTPRequest.h 2009-01-05 00:47:23 UTC (rev 2437)
+++ box/trunk/lib/httpserver/HTTPRequest.h 2009-01-05 00:48:01 UTC (rev 2438)
@@ -13,6 +13,9 @@
#include <string>
#include <map>
+#include "CollectInBufferStream.h"
+
+class HTTPResponse;
class IOStream;
class IOStreamGetLine;
@@ -24,7 +27,7 @@
// Created: 26/3/04
//
// --------------------------------------------------------------------------
-class HTTPRequest
+class HTTPRequest : public CollectInBufferStream
{
public:
enum Method
@@ -33,7 +36,8 @@
Method_UNKNOWN = 0,
Method_GET = 1,
Method_HEAD = 2,
- Method_POST = 3
+ Method_POST = 3,
+ Method_PUT = 4
};
HTTPRequest();
@@ -56,7 +60,10 @@
};
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,8 +95,21 @@
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;
+ }
-
// --------------------------------------------------------------------------
//
// Function
@@ -109,12 +129,12 @@
{
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 @@
CookieJar_t *mpCookies;
bool mClientKeepAliveRequested;
std::vector<Header> mExtraHeaders;
+ bool mExpectContinue;
+ IOStream* mpStreamToReadFrom;
};
#endif // HTTPREQUEST__H