Removed most HTTP stuff. It doesn't seem like the appropriate
choice for server control. May later provide some other means for controlling the synergy server remotely.
This commit is contained in:
parent
4c7e524896
commit
618aa7fedd
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -71,7 +71,7 @@ LINK32=link.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
|
|
@ -45,7 +45,6 @@ synergys_LDADD = \
|
||||||
$(DEPTH)/lib/platform/libplatform.a \
|
$(DEPTH)/lib/platform/libplatform.a \
|
||||||
$(DEPTH)/lib/synergy/libsynergy.a \
|
$(DEPTH)/lib/synergy/libsynergy.a \
|
||||||
$(DEPTH)/lib/net/libnet.a \
|
$(DEPTH)/lib/net/libnet.a \
|
||||||
$(DEPTH)/lib/http/libhttp.a \
|
|
||||||
$(DEPTH)/lib/io/libio.a \
|
$(DEPTH)/lib/io/libio.a \
|
||||||
$(DEPTH)/lib/mt/libmt.a \
|
$(DEPTH)/lib/mt/libmt.a \
|
||||||
$(DEPTH)/lib/base/libbase.a \
|
$(DEPTH)/lib/base/libbase.a \
|
||||||
|
@ -63,7 +62,6 @@ INCLUDES = \
|
||||||
-I$(VDEPTH)/lib/base \
|
-I$(VDEPTH)/lib/base \
|
||||||
-I$(VDEPTH)/lib/mt \
|
-I$(VDEPTH)/lib/mt \
|
||||||
-I$(VDEPTH)/lib/io \
|
-I$(VDEPTH)/lib/io \
|
||||||
-I$(VDEPTH)/lib/http \
|
|
||||||
-I$(VDEPTH)/lib/net \
|
-I$(VDEPTH)/lib/net \
|
||||||
-I$(VDEPTH)/lib/synergy \
|
-I$(VDEPTH)/lib/synergy \
|
||||||
-I$(VDEPTH)/lib/platform \
|
-I$(VDEPTH)/lib/platform \
|
||||||
|
|
|
@ -43,7 +43,7 @@ RSC=rc.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||||
|
@ -70,7 +70,7 @@ LINK32=link.exe
|
||||||
# PROP Ignore_Export_Lib 0
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\http" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\..\lib\common" /I "..\..\lib\arch" /I "..\..\lib\base" /I "..\..\lib\mt" /I "..\..\lib\io" /I "..\..\lib\net" /I "..\..\lib\synergy" /I "..\..\lib\platform" /I "..\..\lib\server" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||||
|
|
|
@ -107,7 +107,6 @@ lib/base/Makefile
|
||||||
lib/common/Makefile
|
lib/common/Makefile
|
||||||
lib/mt/Makefile
|
lib/mt/Makefile
|
||||||
lib/io/Makefile
|
lib/io/Makefile
|
||||||
lib/http/Makefile
|
|
||||||
lib/net/Makefile
|
lib/net/Makefile
|
||||||
lib/synergy/Makefile
|
lib/synergy/Makefile
|
||||||
lib/platform/Makefile
|
lib/platform/Makefile
|
||||||
|
|
|
@ -21,7 +21,6 @@ SUBDIRS = \
|
||||||
base \
|
base \
|
||||||
mt \
|
mt \
|
||||||
io \
|
io \
|
||||||
http \
|
|
||||||
net \
|
net \
|
||||||
synergy \
|
synergy \
|
||||||
platform \
|
platform \
|
||||||
|
|
|
@ -1,658 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "CHTTPProtocol.h"
|
|
||||||
#include "XHTTP.h"
|
|
||||||
#include "IInputStream.h"
|
|
||||||
#include "IOutputStream.h"
|
|
||||||
#include "CLog.h"
|
|
||||||
#include "stdsstream.h"
|
|
||||||
#include <clocale>
|
|
||||||
#include <ctime>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
//
|
|
||||||
// CHTTPRequest
|
|
||||||
//
|
|
||||||
|
|
||||||
CHTTPRequest::CHTTPRequest()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
CHTTPRequest::~CHTTPRequest()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHTTPRequest::insertHeader(const CString& name, const CString& value)
|
|
||||||
{
|
|
||||||
CHeaderMap::iterator index = m_headerByName.find(name);
|
|
||||||
if (index != m_headerByName.end()) {
|
|
||||||
index->second->second = value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CHeaderList::iterator pos = m_headers.insert(
|
|
||||||
m_headers.end(), std::make_pair(name, value));
|
|
||||||
m_headerByName.insert(std::make_pair(name, pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHTTPRequest::appendHeader(const CString& name, const CString& value)
|
|
||||||
{
|
|
||||||
CHeaderMap::iterator index = m_headerByName.find(name);
|
|
||||||
if (index != m_headerByName.end()) {
|
|
||||||
index->second->second += ",";
|
|
||||||
index->second->second += value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CHeaderList::iterator pos = m_headers.insert(
|
|
||||||
m_headers.end(), std::make_pair(name, value));
|
|
||||||
m_headerByName.insert(std::make_pair(name, pos));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHTTPRequest::eraseHeader(const CString& name)
|
|
||||||
{
|
|
||||||
CHeaderMap::iterator index = m_headerByName.find(name);
|
|
||||||
if (index != m_headerByName.end()) {
|
|
||||||
m_headers.erase(index->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHTTPRequest::isHeader(const CString& name) const
|
|
||||||
{
|
|
||||||
return (m_headerByName.find(name) != m_headerByName.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CHTTPRequest::getHeader(const CString& name) const
|
|
||||||
{
|
|
||||||
CHeaderMap::const_iterator index = m_headerByName.find(name);
|
|
||||||
if (index != m_headerByName.end()) {
|
|
||||||
return index->second->second;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return CString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// CHTTPProtocol
|
|
||||||
//
|
|
||||||
|
|
||||||
CHTTPRequest*
|
|
||||||
CHTTPProtocol::readRequest(IInputStream* stream, UInt32 maxSize)
|
|
||||||
{
|
|
||||||
CString scratch;
|
|
||||||
|
|
||||||
// note if we should limit the request size
|
|
||||||
const bool checkSize = (maxSize > 0);
|
|
||||||
|
|
||||||
// parse request line by line
|
|
||||||
CHTTPRequest* request = new CHTTPRequest;
|
|
||||||
try {
|
|
||||||
CString line;
|
|
||||||
|
|
||||||
// read request line. accept and discard leading empty lines.
|
|
||||||
do {
|
|
||||||
line = readLine(stream, scratch);
|
|
||||||
if (checkSize) {
|
|
||||||
if (line.size() + 2 > maxSize) {
|
|
||||||
throw XHTTP(413);
|
|
||||||
}
|
|
||||||
maxSize -= line.size() + 2;
|
|
||||||
}
|
|
||||||
} while (line.empty());
|
|
||||||
|
|
||||||
// parse request line: <method> <uri> <version>
|
|
||||||
{
|
|
||||||
std::istringstream s(line);
|
|
||||||
s.exceptions(std::ios::goodbit);
|
|
||||||
CString version;
|
|
||||||
s >> request->m_method >> request->m_uri >> version;
|
|
||||||
if (!s || request->m_uri.empty() || version.find("HTTP/") != 0) {
|
|
||||||
LOG((CLOG_DEBUG1 "failed to parse HTTP request line: %s", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse version
|
|
||||||
char dot;
|
|
||||||
s.str(version);
|
|
||||||
s.clear();
|
|
||||||
s.ignore(5);
|
|
||||||
s >> request->m_majorVersion;
|
|
||||||
s.get(dot);
|
|
||||||
s >> request->m_minorVersion;
|
|
||||||
if (!s || dot != '.') {
|
|
||||||
LOG((CLOG_DEBUG1 "failed to parse HTTP request line: %s", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isValidToken(request->m_method)) {
|
|
||||||
LOG((CLOG_DEBUG1 "invalid HTTP method: %s", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
if (request->m_majorVersion < 1 || request->m_minorVersion < 0) {
|
|
||||||
LOG((CLOG_DEBUG1 "invalid HTTP version: %s", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse headers
|
|
||||||
readHeaders(stream, request, false, scratch,
|
|
||||||
checkSize ? &maxSize : NULL);
|
|
||||||
|
|
||||||
// HTTP/1.1 requests must have a Host header
|
|
||||||
if (request->m_majorVersion > 1 ||
|
|
||||||
(request->m_majorVersion == 1 && request->m_minorVersion >= 1)) {
|
|
||||||
if (request->isHeader("Host") == 0) {
|
|
||||||
LOG((CLOG_DEBUG1 "Host header missing"));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// some methods may not have a body. ensure that the headers
|
|
||||||
// that indicate the body length do not exist for those methods
|
|
||||||
// and do exist for others.
|
|
||||||
if ((request->isHeader("Transfer-Encoding") ||
|
|
||||||
request->isHeader("Content-Length")) ==
|
|
||||||
(request->m_method == "GET" ||
|
|
||||||
request->m_method == "HEAD")) {
|
|
||||||
LOG((CLOG_DEBUG1 "HTTP method (%s)/body mismatch", request->m_method.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare to read the body. the length of the body is
|
|
||||||
// determined using, in order:
|
|
||||||
// 1. Transfer-Encoding indicates a "chunked" transfer
|
|
||||||
// 2. Content-Length is present
|
|
||||||
// Content-Length is ignored for "chunked" transfers.
|
|
||||||
CString header;
|
|
||||||
if (!(header = request->getHeader("Transfer-Encoding")).empty()) {
|
|
||||||
// we only understand "chunked" encodings
|
|
||||||
if (!CStringUtil::CaselessCmp::equal(header, "chunked")) {
|
|
||||||
LOG((CLOG_DEBUG1 "unsupported Transfer-Encoding %s", header.c_str()));
|
|
||||||
throw XHTTP(501);
|
|
||||||
}
|
|
||||||
|
|
||||||
// chunked encoding
|
|
||||||
UInt32 oldSize;
|
|
||||||
do {
|
|
||||||
oldSize = request->m_body.size();
|
|
||||||
request->m_body += readChunk(stream, scratch,
|
|
||||||
checkSize ? &maxSize : NULL);
|
|
||||||
} while (request->m_body.size() != oldSize);
|
|
||||||
|
|
||||||
// read footer
|
|
||||||
readHeaders(stream, request, true, scratch,
|
|
||||||
checkSize ? &maxSize : NULL);
|
|
||||||
|
|
||||||
// remove "chunked" from Transfer-Encoding and set the
|
|
||||||
// Content-Length.
|
|
||||||
std::ostringstream s;
|
|
||||||
s << std::dec << request->m_body.size();
|
|
||||||
request->eraseHeader("Transfer-Encoding");
|
|
||||||
request->insertHeader("Content-Length", s.str());
|
|
||||||
}
|
|
||||||
else if (!(header = request->getHeader("Content-Length")).empty()) {
|
|
||||||
// parse content-length
|
|
||||||
UInt32 length;
|
|
||||||
{
|
|
||||||
std::istringstream s(header);
|
|
||||||
s.exceptions(std::ios::goodbit);
|
|
||||||
s >> length;
|
|
||||||
if (!s) {
|
|
||||||
LOG((CLOG_DEBUG1 "cannot parse Content-Length", header.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check against expected size
|
|
||||||
if (checkSize && length > maxSize) {
|
|
||||||
throw XHTTP(413);
|
|
||||||
}
|
|
||||||
|
|
||||||
// use content length
|
|
||||||
request->m_body = readBlock(stream, length, scratch);
|
|
||||||
if (request->m_body.size() != length) {
|
|
||||||
// length must match size of body
|
|
||||||
LOG((CLOG_DEBUG1 "Content-Length/actual length mismatch (%d vs %d)", length, request->m_body.size()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
delete request;
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHTTPProtocol::reply(IOutputStream* stream, CHTTPReply& reply)
|
|
||||||
{
|
|
||||||
// suppress body for certain replies
|
|
||||||
bool hasBody = true;
|
|
||||||
if ((reply.m_status / 100) == 1 ||
|
|
||||||
reply.m_status == 204 ||
|
|
||||||
reply.m_status == 304) {
|
|
||||||
hasBody = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust headers
|
|
||||||
for (CHTTPReply::CHeaderList::iterator
|
|
||||||
index = reply.m_headers.begin();
|
|
||||||
index != reply.m_headers.end(); ) {
|
|
||||||
const CString& header = index->first;
|
|
||||||
|
|
||||||
// remove certain headers
|
|
||||||
if (CStringUtil::CaselessCmp::equal(header, "Content-Length") ||
|
|
||||||
CStringUtil::CaselessCmp::equal(header, "Date") ||
|
|
||||||
CStringUtil::CaselessCmp::equal(header, "Transfer-Encoding")) {
|
|
||||||
// FIXME -- Transfer-Encoding should be left as-is if
|
|
||||||
// not "chunked" and if the version is 1.1 or up.
|
|
||||||
index = reply.m_headers.erase(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep as-is
|
|
||||||
else {
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write reply header
|
|
||||||
std::ostringstream s;
|
|
||||||
s << "HTTP/" << reply.m_majorVersion << "." <<
|
|
||||||
reply.m_minorVersion << " " <<
|
|
||||||
reply.m_status << " " <<
|
|
||||||
reply.m_reason << "\r\n";
|
|
||||||
|
|
||||||
// get date
|
|
||||||
// FIXME -- should use C++ locale stuff but VC++ time_put is broken.
|
|
||||||
// FIXME -- double check that VC++ is broken
|
|
||||||
char date[30];
|
|
||||||
{
|
|
||||||
const char* oldLocale = setlocale(LC_TIME, "C");
|
|
||||||
time_t t = time(NULL);
|
|
||||||
#if HAVE_GMTIME_R
|
|
||||||
struct tm tm;
|
|
||||||
struct tm* tmp = &tm;
|
|
||||||
gmtime_r(&t, tmp);
|
|
||||||
#else
|
|
||||||
struct tm* tmp = gmtime(&t);
|
|
||||||
#endif
|
|
||||||
strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", tmp);
|
|
||||||
setlocale(LC_TIME, oldLocale);
|
|
||||||
}
|
|
||||||
|
|
||||||
// write headers
|
|
||||||
s << "Date: " << date << "\r\n";
|
|
||||||
for (CHTTPReply::CHeaderList::const_iterator
|
|
||||||
index = reply.m_headers.begin();
|
|
||||||
index != reply.m_headers.end(); ++index) {
|
|
||||||
s << index->first << ": " << index->second << "\r\n";
|
|
||||||
}
|
|
||||||
if (hasBody) {
|
|
||||||
s << "Content-Length: " << reply.m_body.size() << "\r\n";
|
|
||||||
}
|
|
||||||
s << "Connection: close\r\n";
|
|
||||||
|
|
||||||
// write end of headers
|
|
||||||
s << "\r\n";
|
|
||||||
|
|
||||||
// write to stream
|
|
||||||
stream->write(s.str().data(), s.str().size());
|
|
||||||
|
|
||||||
// write body. replies to HEAD method never have a body (though
|
|
||||||
// they do have the Content-Length header).
|
|
||||||
if (hasBody && reply.m_method != "HEAD") {
|
|
||||||
stream->write(reply.m_body.data(), reply.m_body.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHTTPProtocol::parseFormData(const CHTTPRequest& request, CFormParts& parts)
|
|
||||||
{
|
|
||||||
static const char formData[] = "multipart/form-data";
|
|
||||||
static const char boundary[] = "boundary=";
|
|
||||||
static const char disposition[] = "Content-Disposition:";
|
|
||||||
static const char nameAttr[] = "name=";
|
|
||||||
static const char quote[] = "\"";
|
|
||||||
|
|
||||||
// find the Content-Type header
|
|
||||||
const CString contentType = request.getHeader("Content-Type");
|
|
||||||
if (contentType.empty()) {
|
|
||||||
// missing required Content-Type header
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse type
|
|
||||||
CString::const_iterator index = std::search(
|
|
||||||
contentType.begin(), contentType.end(),
|
|
||||||
formData, formData + sizeof(formData) - 1,
|
|
||||||
CStringUtil::CaselessCmp::cmpEqual);
|
|
||||||
if (index == contentType.end()) {
|
|
||||||
// not form-data
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
index += sizeof(formData) - 1;
|
|
||||||
index = std::search(index, contentType.end(),
|
|
||||||
boundary, boundary + sizeof(boundary) - 1,
|
|
||||||
CStringUtil::CaselessCmp::cmpEqual);
|
|
||||||
if (index == contentType.end()) {
|
|
||||||
// no boundary
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
CString delimiter = contentType.c_str() +
|
|
||||||
(index - contentType.begin()) +
|
|
||||||
sizeof(boundary) - 1;
|
|
||||||
|
|
||||||
// find first delimiter
|
|
||||||
const CString& body = request.m_body;
|
|
||||||
CString::size_type partIndex = body.find(delimiter);
|
|
||||||
if (partIndex == CString::npos) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip over it
|
|
||||||
partIndex += delimiter.size();
|
|
||||||
|
|
||||||
// prepend CRLF-- to delimiter
|
|
||||||
delimiter = "\r\n--" + delimiter;
|
|
||||||
|
|
||||||
// parse parts until there are no more
|
|
||||||
for (;;) {
|
|
||||||
// is it the last part?
|
|
||||||
if (body.size() >= partIndex + 2 &&
|
|
||||||
body[partIndex ] == '-' &&
|
|
||||||
body[partIndex + 1] == '-') {
|
|
||||||
// found last part. ignore trailing data, if any.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the end of this part
|
|
||||||
CString::size_type nextPart = body.find(delimiter, partIndex);
|
|
||||||
if (nextPart == CString::npos) {
|
|
||||||
// no terminator
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find end of headers
|
|
||||||
CString::size_type endOfHeaders = body.find("\r\n\r\n", partIndex);
|
|
||||||
if (endOfHeaders == CString::npos || endOfHeaders > nextPart) {
|
|
||||||
// bad part
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
endOfHeaders += 2;
|
|
||||||
|
|
||||||
// now find Content-Disposition
|
|
||||||
index = std::search(body.begin() + partIndex,
|
|
||||||
body.begin() + endOfHeaders,
|
|
||||||
disposition,
|
|
||||||
disposition + sizeof(disposition) - 1,
|
|
||||||
CStringUtil::CaselessCmp::cmpEqual);
|
|
||||||
if (index == contentType.begin() + endOfHeaders) {
|
|
||||||
// bad part
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the name in the Content-Disposition
|
|
||||||
CString::size_type endOfHeader = body.find("\r\n",
|
|
||||||
index - body.begin());
|
|
||||||
if (endOfHeader >= endOfHeaders) {
|
|
||||||
// bad part
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
index = std::search(index, body.begin() + endOfHeader,
|
|
||||||
nameAttr, nameAttr + sizeof(nameAttr) - 1,
|
|
||||||
CStringUtil::CaselessCmp::cmpEqual);
|
|
||||||
if (index == body.begin() + endOfHeader) {
|
|
||||||
// no name
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract the name
|
|
||||||
CString name;
|
|
||||||
index += sizeof(nameAttr) - 1;
|
|
||||||
if (*index == quote[0]) {
|
|
||||||
// quoted name
|
|
||||||
++index;
|
|
||||||
CString::size_type namePos = index - body.begin();
|
|
||||||
index = std::search(index, body.begin() + endOfHeader,
|
|
||||||
quote, quote + 1,
|
|
||||||
CStringUtil::CaselessCmp::cmpEqual);
|
|
||||||
if (index == body.begin() + endOfHeader) {
|
|
||||||
// missing close quote
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
name = body.substr(namePos, index - body.begin() - namePos);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// unquoted name
|
|
||||||
name = body.substr(index - body.begin(),
|
|
||||||
body.find_first_of(" \t\r\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// save part. add 2 to endOfHeaders to skip CRLF.
|
|
||||||
parts.insert(std::make_pair(name, body.substr(endOfHeaders + 2,
|
|
||||||
nextPart - (endOfHeaders + 2))));
|
|
||||||
|
|
||||||
// move to next part
|
|
||||||
partIndex = nextPart + delimiter.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
// should've found the last delimiter inside the loop but we did not
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CHTTPProtocol::readLine(IInputStream* stream, CString& tmpBuffer)
|
|
||||||
{
|
|
||||||
// read up to and including a CRLF from stream, using whatever
|
|
||||||
// is in tmpBuffer as if it were at the head of the stream.
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
// scan tmpBuffer for CRLF
|
|
||||||
CString::size_type newline = tmpBuffer.find("\r\n");
|
|
||||||
if (newline != CString::npos) {
|
|
||||||
// copy line without the CRLF
|
|
||||||
CString line = tmpBuffer.substr(0, newline);
|
|
||||||
|
|
||||||
// discard line and CRLF from tmpBuffer
|
|
||||||
tmpBuffer.erase(0, newline + 2);
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read more from stream
|
|
||||||
char buffer[4096];
|
|
||||||
UInt32 n = stream->read(buffer, sizeof(buffer), -1.0);
|
|
||||||
if (n == 0) {
|
|
||||||
// stream is empty. return what's leftover.
|
|
||||||
CString line = tmpBuffer;
|
|
||||||
tmpBuffer.erase();
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
// append stream data
|
|
||||||
tmpBuffer.append(buffer, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CHTTPProtocol::readBlock(IInputStream* stream,
|
|
||||||
UInt32 numBytes, CString& tmpBuffer)
|
|
||||||
{
|
|
||||||
CString data;
|
|
||||||
|
|
||||||
// read numBytes from stream, using whatever is in tmpBuffer as
|
|
||||||
// if it were at the head of the stream.
|
|
||||||
if (tmpBuffer.size() > 0) {
|
|
||||||
// ignore stream if there's enough data in tmpBuffer
|
|
||||||
if (tmpBuffer.size() >= numBytes) {
|
|
||||||
data = tmpBuffer.substr(0, numBytes);
|
|
||||||
tmpBuffer.erase(0, numBytes);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move everything out of tmpBuffer into data
|
|
||||||
data = tmpBuffer;
|
|
||||||
tmpBuffer.erase();
|
|
||||||
}
|
|
||||||
|
|
||||||
// account for bytes read so far
|
|
||||||
assert(data.size() < numBytes);
|
|
||||||
numBytes -= data.size();
|
|
||||||
|
|
||||||
// read until we have all the requested data
|
|
||||||
while (numBytes > 0) {
|
|
||||||
// read max(4096, bytes_left) bytes into buffer
|
|
||||||
char buffer[4096];
|
|
||||||
UInt32 n = sizeof(buffer);
|
|
||||||
if (n > numBytes) {
|
|
||||||
n = numBytes;
|
|
||||||
}
|
|
||||||
n = stream->read(buffer, n, -1.0);
|
|
||||||
|
|
||||||
// if stream is empty then return what we've got so far
|
|
||||||
if (n == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// append stream data
|
|
||||||
data.append(buffer, n);
|
|
||||||
numBytes -= n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
CHTTPProtocol::readChunk(IInputStream* stream,
|
|
||||||
CString& tmpBuffer, UInt32* maxSize)
|
|
||||||
{
|
|
||||||
CString line;
|
|
||||||
|
|
||||||
// get chunk header
|
|
||||||
line = readLine(stream, tmpBuffer);
|
|
||||||
|
|
||||||
// parse chunk size
|
|
||||||
UInt32 size;
|
|
||||||
{
|
|
||||||
std::istringstream s(line);
|
|
||||||
s.exceptions(std::ios::goodbit);
|
|
||||||
s >> std::hex >> size;
|
|
||||||
if (!s) {
|
|
||||||
LOG((CLOG_DEBUG1 "cannot parse chunk size", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (size == 0) {
|
|
||||||
return CString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// check size
|
|
||||||
if (maxSize != NULL) {
|
|
||||||
if (line.size() + 2 + size + 2 > *maxSize) {
|
|
||||||
throw XHTTP(413);
|
|
||||||
}
|
|
||||||
maxSize -= line.size() + 2 + size + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read size bytes
|
|
||||||
CString data = readBlock(stream, size, tmpBuffer);
|
|
||||||
if (data.size() != size) {
|
|
||||||
LOG((CLOG_DEBUG1 "expected/actual chunk size mismatch", size, data.size()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read an discard CRLF
|
|
||||||
line = readLine(stream, tmpBuffer);
|
|
||||||
if (!line.empty()) {
|
|
||||||
LOG((CLOG_DEBUG1 "missing CRLF after chunk"));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
CHTTPProtocol::readHeaders(IInputStream* stream,
|
|
||||||
CHTTPRequest* request, bool isFooter,
|
|
||||||
CString& tmpBuffer, UInt32* maxSize)
|
|
||||||
{
|
|
||||||
// parse headers. done with headers when we get a blank line.
|
|
||||||
CString name;
|
|
||||||
CString line = readLine(stream, tmpBuffer);
|
|
||||||
while (!line.empty()) {
|
|
||||||
// check size
|
|
||||||
if (maxSize != NULL) {
|
|
||||||
if (line.size() + 2 > *maxSize) {
|
|
||||||
throw XHTTP(413);
|
|
||||||
}
|
|
||||||
*maxSize -= line.size() + 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if line starts with space or tab then append it to the
|
|
||||||
// previous header. if there is no previous header then
|
|
||||||
// throw.
|
|
||||||
if (line[0] == ' ' || line[0] == '\t') {
|
|
||||||
if (name.empty()) {
|
|
||||||
LOG((CLOG_DEBUG1 "first header is a continuation"));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
request->appendHeader(name, line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// line should have the form: <name>:[<value>]
|
|
||||||
else {
|
|
||||||
// parse
|
|
||||||
CString value;
|
|
||||||
std::istringstream s(line);
|
|
||||||
s.exceptions(std::ios::goodbit);
|
|
||||||
std::getline(s, name, ':');
|
|
||||||
if (!s || !isValidToken(name)) {
|
|
||||||
LOG((CLOG_DEBUG1 "invalid header: %s", line.c_str()));
|
|
||||||
throw XHTTP(400);
|
|
||||||
}
|
|
||||||
std::getline(s, value);
|
|
||||||
|
|
||||||
// check validity of name
|
|
||||||
if (isFooter) {
|
|
||||||
// FIXME -- only certain names are allowed in footers
|
|
||||||
// but which ones?
|
|
||||||
}
|
|
||||||
|
|
||||||
request->appendHeader(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// next header
|
|
||||||
line = readLine(stream, tmpBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CHTTPProtocol::isValidToken(const CString& token)
|
|
||||||
{
|
|
||||||
return (token.find("()<>@,;:\\\"/[]?={} "
|
|
||||||
"\0\1\2\3\4\5\6\7"
|
|
||||||
"\10\11\12\13\14\15\16\17"
|
|
||||||
"\20\21\22\23\24\25\26\27"
|
|
||||||
"\30\31\32\33\34\35\36\37\177") == CString::npos);
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CHTTPPROTOCOL_H
|
|
||||||
#define CHTTPPROTOCOL_H
|
|
||||||
|
|
||||||
#include "CString.h"
|
|
||||||
#include "CStringUtil.h"
|
|
||||||
#include "BasicTypes.h"
|
|
||||||
#include "stdlist.h"
|
|
||||||
#include "stdmap.h"
|
|
||||||
#include "stdvector.h"
|
|
||||||
|
|
||||||
class IInputStream;
|
|
||||||
class IOutputStream;
|
|
||||||
|
|
||||||
//! HTTP request type
|
|
||||||
/*!
|
|
||||||
This class encapsulates an HTTP request.
|
|
||||||
*/
|
|
||||||
class CHTTPRequest {
|
|
||||||
private:
|
|
||||||
typedef std::list<std::pair<CString, CString> > CHeaderList;
|
|
||||||
public:
|
|
||||||
//! Iterator on headers
|
|
||||||
/*!
|
|
||||||
An iterator on the headers. Each element is a std::pair; first is
|
|
||||||
the header name as a CString, second is the header value as a CString.
|
|
||||||
*/
|
|
||||||
typedef CHeaderList::const_iterator const_iterator;
|
|
||||||
|
|
||||||
CHTTPRequest();
|
|
||||||
~CHTTPRequest();
|
|
||||||
|
|
||||||
//! @name manipulators
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Insert header
|
|
||||||
/*!
|
|
||||||
Add a header by name replacing the existing header, if any.
|
|
||||||
Headers are sent in the order they're inserted. Replacing
|
|
||||||
a header does not change its original position in the order.
|
|
||||||
*/
|
|
||||||
void insertHeader(const CString& name, const CString& value);
|
|
||||||
|
|
||||||
//! Append header
|
|
||||||
/*!
|
|
||||||
Append a header. Equivalent to insertHeader() if the header
|
|
||||||
doesn't exist, otherwise it appends a comma and the value to
|
|
||||||
the existing header.
|
|
||||||
*/
|
|
||||||
void appendHeader(const CString& name, const CString& value);
|
|
||||||
|
|
||||||
//! Remove header
|
|
||||||
/*!
|
|
||||||
Remove a header by name. Does nothing if the header doesn't exist.
|
|
||||||
*/
|
|
||||||
void eraseHeader(const CString& name);
|
|
||||||
|
|
||||||
//@}
|
|
||||||
//! @name accessors
|
|
||||||
//@{
|
|
||||||
|
|
||||||
//! Check header existence
|
|
||||||
/*!
|
|
||||||
Returns true iff the header exists.
|
|
||||||
*/
|
|
||||||
bool isHeader(const CString& name) const;
|
|
||||||
|
|
||||||
//! Get header
|
|
||||||
/*!
|
|
||||||
Get a header by name. Returns the empty string if the header
|
|
||||||
doesn't exist.
|
|
||||||
*/
|
|
||||||
CString getHeader(const CString& name) const;
|
|
||||||
|
|
||||||
// headers are iterated in the order they were added.
|
|
||||||
//! Get beginning header iterator
|
|
||||||
const_iterator begin() const { return m_headers.begin(); }
|
|
||||||
//! Get ending header iterator
|
|
||||||
const_iterator end() const { return m_headers.end(); }
|
|
||||||
|
|
||||||
//@}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// note -- these members are public for convenience
|
|
||||||
//! The HTTP method
|
|
||||||
CString m_method;
|
|
||||||
//! The HTTP URI
|
|
||||||
CString m_uri;
|
|
||||||
//! The HTTP major version number
|
|
||||||
SInt32 m_majorVersion;
|
|
||||||
//! The HTTP minor version number
|
|
||||||
SInt32 m_minorVersion;
|
|
||||||
//! The HTTP body, after transfer decoding
|
|
||||||
CString m_body;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::map<CString, CHeaderList::iterator,
|
|
||||||
CStringUtil::CaselessCmp> CHeaderMap;
|
|
||||||
|
|
||||||
CHeaderList m_headers;
|
|
||||||
CHeaderMap m_headerByName;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! HTTP reply type
|
|
||||||
/*!
|
|
||||||
This class encapsulates an HTTP reply.
|
|
||||||
*/
|
|
||||||
class CHTTPReply {
|
|
||||||
public:
|
|
||||||
//! Header list
|
|
||||||
/*!
|
|
||||||
The type of the reply header list. Each pair is the header name
|
|
||||||
and value, respectively for first and second.
|
|
||||||
*/
|
|
||||||
typedef std::vector<std::pair<CString, CString> > CHeaderList;
|
|
||||||
|
|
||||||
// note -- these members are public for convenience
|
|
||||||
//! The HTTP major version number
|
|
||||||
SInt32 m_majorVersion;
|
|
||||||
//! The HTTP minor version number
|
|
||||||
SInt32 m_minorVersion;
|
|
||||||
//! The HTTP status code
|
|
||||||
SInt32 m_status;
|
|
||||||
//! The HTTP reason phrase
|
|
||||||
CString m_reason;
|
|
||||||
//! The HTTP method
|
|
||||||
CString m_method;
|
|
||||||
//! The HTTP headers
|
|
||||||
CHeaderList m_headers;
|
|
||||||
//! The HTTP body
|
|
||||||
CString m_body;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! HTTP protocol utilities
|
|
||||||
/*!
|
|
||||||
This class provides utility functions for HTTP.
|
|
||||||
*/
|
|
||||||
class CHTTPProtocol {
|
|
||||||
public:
|
|
||||||
//! Multipart form parts
|
|
||||||
/*!
|
|
||||||
Each element is the contents of a multipart form part indexed by
|
|
||||||
it's name.
|
|
||||||
*/
|
|
||||||
typedef std::map<CString, CString> CFormParts;
|
|
||||||
|
|
||||||
//! Read HTTP request
|
|
||||||
/*!
|
|
||||||
Read and parse an HTTP request. The result is returned in a
|
|
||||||
CHTTPRequest which the client must delete. Throws an
|
|
||||||
XHTTP if there was a parse error. Throws an XIO exception
|
|
||||||
if there was a read error. If \c maxSize is greater than
|
|
||||||
zero and the request is larger than \c maxSize bytes then
|
|
||||||
throws XHTTP(413) (request entity too large).
|
|
||||||
*/
|
|
||||||
static CHTTPRequest* readRequest(IInputStream*, UInt32 maxSize = 0);
|
|
||||||
|
|
||||||
//! Send HTTP response
|
|
||||||
/*!
|
|
||||||
Send an HTTP reply. The Content-Length and Date headers are set
|
|
||||||
automatically.
|
|
||||||
*/
|
|
||||||
static void reply(IOutputStream*, CHTTPReply&);
|
|
||||||
|
|
||||||
//! Parse multipart form data
|
|
||||||
/*!
|
|
||||||
Parse a multipart/form-data body into its parts. Returns true
|
|
||||||
iff the entire body was correctly parsed.
|
|
||||||
*/
|
|
||||||
// FIXME -- name/value pairs insufficient to save part headers
|
|
||||||
static bool parseFormData(const CHTTPRequest&,
|
|
||||||
CFormParts& parts);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static CString readLine(IInputStream*, CString& tmpBuffer);
|
|
||||||
static CString readBlock(IInputStream*,
|
|
||||||
UInt32 numBytes, CString& tmpBuffer);
|
|
||||||
static CString readChunk(IInputStream*, CString& tmpBuffer,
|
|
||||||
UInt32* maxSize);
|
|
||||||
static void readHeaders(IInputStream*,
|
|
||||||
CHTTPRequest*, bool isFooter,
|
|
||||||
CString& tmpBuffer,
|
|
||||||
UInt32* maxSize);
|
|
||||||
|
|
||||||
static bool isValidToken(const CString&);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,39 +0,0 @@
|
||||||
# synergy -- mouse and keyboard sharing utility
|
|
||||||
# Copyright (C) 2002 Chris Schoeneman
|
|
||||||
#
|
|
||||||
# This package is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU General Public License
|
|
||||||
# found in the file COPYING that should have accompanied this file.
|
|
||||||
#
|
|
||||||
# This package is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
|
|
||||||
## Process this file with automake to produce Makefile.in
|
|
||||||
NULL =
|
|
||||||
DEPTH = ../..
|
|
||||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
http.dsp \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = \
|
|
||||||
Makefile.in \
|
|
||||||
$(NULL)
|
|
||||||
|
|
||||||
noinst_LIBRARIES = libhttp.a
|
|
||||||
libhttp_a_SOURCES = \
|
|
||||||
CHTTPProtocol.cpp \
|
|
||||||
XHTTP.cpp \
|
|
||||||
CHTTPProtocol.h \
|
|
||||||
XHTTP.h \
|
|
||||||
$(NULL)
|
|
||||||
INCLUDES = \
|
|
||||||
-I$(VDEPTH)/lib/common \
|
|
||||||
-I$(VDEPTH)/lib/arch \
|
|
||||||
-I$(VDEPTH)/lib/base \
|
|
||||||
-I$(VDEPTH)/lib/mt \
|
|
||||||
-I$(VDEPTH)/lib/io \
|
|
||||||
$(NULL)
|
|
|
@ -1,135 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "XHTTP.h"
|
|
||||||
#include "CHTTPProtocol.h"
|
|
||||||
#include "CStringUtil.h"
|
|
||||||
#include "stdsstream.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// XHTTP
|
|
||||||
//
|
|
||||||
|
|
||||||
XHTTP::XHTTP(SInt32 statusCode) :
|
|
||||||
XBase(),
|
|
||||||
m_status(statusCode),
|
|
||||||
m_reason(getReason(statusCode))
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
XHTTP::XHTTP(SInt32 statusCode, const CString& reasonPhrase) :
|
|
||||||
XBase(),
|
|
||||||
m_status(statusCode),
|
|
||||||
m_reason(reasonPhrase)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
XHTTP::~XHTTP()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
SInt32
|
|
||||||
XHTTP::getStatus() const
|
|
||||||
{
|
|
||||||
return m_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
XHTTP::getReason() const
|
|
||||||
{
|
|
||||||
return m_reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
XHTTP::addHeaders(CHTTPReply&) const
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
CString
|
|
||||||
XHTTP::getWhat() const throw()
|
|
||||||
{
|
|
||||||
const char* reason;
|
|
||||||
if (m_reason.empty()) {
|
|
||||||
reason = getReason(m_status);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reason = m_reason.c_str();
|
|
||||||
}
|
|
||||||
return format("XHTTP", "%{1} %{2}",
|
|
||||||
CStringUtil::print("%d", m_status).c_str(),
|
|
||||||
reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char*
|
|
||||||
XHTTP::getReason(SInt32 status)
|
|
||||||
{
|
|
||||||
switch (status) {
|
|
||||||
case 300: return "Multiple Choices";
|
|
||||||
case 301: return "Moved Permanently";
|
|
||||||
case 302: return "Moved Temporarily";
|
|
||||||
case 303: return "See Other";
|
|
||||||
case 304: return "Not Modified";
|
|
||||||
case 305: return "Use Proxy";
|
|
||||||
case 400: return "Bad Request";
|
|
||||||
case 401: return "Unauthorized";
|
|
||||||
case 402: return "Payment Required";
|
|
||||||
case 403: return "Forbidden";
|
|
||||||
case 404: return "Not Found";
|
|
||||||
case 405: return "Method Not Allowed";
|
|
||||||
case 406: return "Not Acceptable";
|
|
||||||
case 407: return "Proxy Authentication Required";
|
|
||||||
case 408: return "Request Time-out";
|
|
||||||
case 409: return "Conflict";
|
|
||||||
case 410: return "Gone";
|
|
||||||
case 411: return "Length Required";
|
|
||||||
case 412: return "Precondition Failed";
|
|
||||||
case 413: return "Request Entity Too Large";
|
|
||||||
case 414: return "Request-URI Too Large";
|
|
||||||
case 415: return "Unsupported Media Type";
|
|
||||||
case 500: return "Internal Server Error";
|
|
||||||
case 501: return "Not Implemented";
|
|
||||||
case 502: return "Bad Gateway";
|
|
||||||
case 503: return "Service Unavailable";
|
|
||||||
case 504: return "Gateway Time-out";
|
|
||||||
case 505: return "HTTP Version not supported";
|
|
||||||
default: return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// XHTTPAllow
|
|
||||||
//
|
|
||||||
|
|
||||||
XHTTPAllow::XHTTPAllow(const CString& allowedMethods) :
|
|
||||||
XHTTP(405),
|
|
||||||
m_allowed(allowedMethods)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
XHTTPAllow::~XHTTPAllow()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
XHTTPAllow::addHeaders(CHTTPReply& reply) const
|
|
||||||
{
|
|
||||||
reply.m_headers.push_back(std::make_pair(CString("Allow"), m_allowed));
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* synergy -- mouse and keyboard sharing utility
|
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
|
||||||
*
|
|
||||||
* This package is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* found in the file COPYING that should have accompanied this file.
|
|
||||||
*
|
|
||||||
* This package is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef XHTTP_H
|
|
||||||
#define XHTTP_H
|
|
||||||
|
|
||||||
#include "BasicTypes.h"
|
|
||||||
#include "XBase.h"
|
|
||||||
|
|
||||||
class CHTTPReply;
|
|
||||||
|
|
||||||
//! Generic HTTP exception
|
|
||||||
class XHTTP : public XBase {
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
Use the HTTP \c statusCode as the failure reason.
|
|
||||||
*/
|
|
||||||
XHTTP(SInt32 statusCode);
|
|
||||||
/*!
|
|
||||||
Use the HTTP \c statusCode as the failure reason. Use \c reasonPhrase
|
|
||||||
as the human readable reason for the failure.
|
|
||||||
*/
|
|
||||||
XHTTP(SInt32 statusCode, const CString& reasonPhrase);
|
|
||||||
~XHTTP();
|
|
||||||
|
|
||||||
//@{
|
|
||||||
//! @name accessors
|
|
||||||
|
|
||||||
//! Get the HTTP status code
|
|
||||||
SInt32 getStatus() const;
|
|
||||||
|
|
||||||
//! Get the reason phrase
|
|
||||||
CString getReason() const;
|
|
||||||
|
|
||||||
//! Modify reply for error
|
|
||||||
/*!
|
|
||||||
Override to modify an HTTP reply to further describe the error.
|
|
||||||
*/
|
|
||||||
virtual void addHeaders(CHTTPReply&) const;
|
|
||||||
|
|
||||||
//@}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual CString getWhat() const throw();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const char* getReason(SInt32 status);
|
|
||||||
|
|
||||||
private:
|
|
||||||
SInt32 m_status;
|
|
||||||
CString m_reason;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! HTTP exception indicating an unsupported method
|
|
||||||
class XHTTPAllow : public XHTTP {
|
|
||||||
public:
|
|
||||||
/*!
|
|
||||||
\c allowedMethods is added as an `Allow' header to a reply in
|
|
||||||
addHeaders().
|
|
||||||
*/
|
|
||||||
XHTTPAllow(const CString& allowedMethods);
|
|
||||||
~XHTTPAllow();
|
|
||||||
|
|
||||||
// XHTTP overrides
|
|
||||||
virtual void addHeaders(CHTTPReply&) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CString m_allowed;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,110 +0,0 @@
|
||||||
# Microsoft Developer Studio Project File - Name="http" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
|
||||||
|
|
||||||
CFG=http - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "http.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "http.mak" CFG="http - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "http - Win32 Release" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE "http - Win32 Debug" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "http - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "http - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\io" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "http - Win32 Release"
|
|
||||||
# Name "http - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\CHTTPProtocol.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\XHTTP.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\CHTTPProtocol.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\XHTTP.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
|
@ -41,7 +41,7 @@ RSC=rc.exe
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||||
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\http" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
# ADD CPP /nologo /MT /W4 /GX /O2 /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||||
|
@ -65,7 +65,7 @@ LIB32=link.exe -lib
|
||||||
# PROP Intermediate_Dir "Debug"
|
# PROP Intermediate_Dir "Debug"
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||||
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\http" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "..\common" /I "..\arch" /I "..\base" /I "..\mt" /I "..\io" /I "..\net" /I "..\synergy" /I "..\platform" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FD /GZ /c
|
||||||
# SUBTRACT CPP /YX
|
# SUBTRACT CPP /YX
|
||||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||||
|
|
18
synergy.dsw
18
synergy.dsw
|
@ -84,18 +84,6 @@ Package=<4>
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Project: "http"=".\lib\HTTP\http.dsp" - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "io"=".\lib\io\io.dsp" - Package Owner=<4>
|
Project: "io"=".\lib\io\io.dsp" - Package Owner=<4>
|
||||||
|
|
||||||
Package=<5>
|
Package=<5>
|
||||||
|
@ -126,9 +114,6 @@ Package=<4>
|
||||||
Project_Dep_Name base
|
Project_Dep_Name base
|
||||||
End Project Dependency
|
End Project Dependency
|
||||||
Begin Project Dependency
|
Begin Project Dependency
|
||||||
Project_Dep_Name http
|
|
||||||
End Project Dependency
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name io
|
Project_Dep_Name io
|
||||||
End Project Dependency
|
End Project Dependency
|
||||||
Begin Project Dependency
|
Begin Project Dependency
|
||||||
|
@ -282,9 +267,6 @@ Package=<4>
|
||||||
Project_Dep_Name base
|
Project_Dep_Name base
|
||||||
End Project Dependency
|
End Project Dependency
|
||||||
Begin Project Dependency
|
Begin Project Dependency
|
||||||
Project_Dep_Name http
|
|
||||||
End Project Dependency
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name io
|
Project_Dep_Name io
|
||||||
End Project Dependency
|
End Project Dependency
|
||||||
Begin Project Dependency
|
Begin Project Dependency
|
||||||
|
|
Loading…
Reference in New Issue