From 6204e62c69c1a05d3beddd0c7397b3f54e576d74 Mon Sep 17 00:00:00 2001 From: Aki Date: Tue, 29 Mar 2022 22:40:57 +0200 Subject: Split Param, Response and Request from HttpServer files --- NetEx/CMakeLists.txt | 3 + NetEx/HttpParam.cpp | 21 ++ NetEx/HttpParam.h | 27 ++ NetEx/HttpRequest.cpp | 497 +++++++++++++++++++++++++++++ NetEx/HttpRequest.h | 76 +++++ NetEx/HttpResponse.cpp | 320 +++++++++++++++++++ NetEx/HttpResponse.h | 99 ++++++ NetEx/HttpServer.cpp | 830 ++----------------------------------------------- NetEx/HttpServer.h | 184 +---------- 9 files changed, 1073 insertions(+), 984 deletions(-) create mode 100644 NetEx/HttpParam.cpp create mode 100644 NetEx/HttpParam.h create mode 100644 NetEx/HttpRequest.cpp create mode 100644 NetEx/HttpRequest.h create mode 100644 NetEx/HttpResponse.cpp create mode 100644 NetEx/HttpResponse.h (limited to 'NetEx') diff --git a/NetEx/CMakeLists.txt b/NetEx/CMakeLists.txt index 5bce174..84d8b0f 100644 --- a/NetEx/CMakeLists.txt +++ b/NetEx/CMakeLists.txt @@ -3,6 +3,9 @@ add_library( NetEx STATIC HttpClient.cpp + HttpParam.cpp + HttpRequest.cpp + HttpResponse.cpp HttpServer.cpp HttpServlet.cpp HttpServletExec.cpp diff --git a/NetEx/HttpParam.cpp b/NetEx/HttpParam.cpp new file mode 100644 index 0000000..933e01a --- /dev/null +++ b/NetEx/HttpParam.cpp @@ -0,0 +1,21 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#include "HttpParam.h" + + +HttpParam::HttpParam(const char* n, const char* v) : + name(n), + value(v) +{ +} + + +int +HttpParam::operator == (const HttpParam& p) const +{ + return name == p.name; +} diff --git a/NetEx/HttpParam.h b/NetEx/HttpParam.h new file mode 100644 index 0000000..8d84296 --- /dev/null +++ b/NetEx/HttpParam.h @@ -0,0 +1,27 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#ifndef HttpParam_h +#define HttpParam_h + +#include "Text.h" + + +class HttpParam +{ +public: + static const char* TYPENAME() { return "HttpParam"; } + + HttpParam(const char* n, const char* v); + + int operator == (const HttpParam& p) const; + + Text name; + Text value; +}; + + +#endif // HttpParam_h diff --git a/NetEx/HttpRequest.cpp b/NetEx/HttpRequest.cpp new file mode 100644 index 0000000..ff24296 --- /dev/null +++ b/NetEx/HttpRequest.cpp @@ -0,0 +1,497 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#include "HttpRequest.h" + +#include +#include +#include + +#include "HttpParam.h" +#include "List.h" +#include "Text.h" + + +HttpRequest::HttpRequest(const char* r) : + method(0) +{ + if (r && *r) + ParseRequest(r); +} + + +HttpRequest::~HttpRequest() +{ + query.destroy(); + headers.destroy(); + cookies.destroy(); +} + + +void +HttpRequest::ParseRequest(Text request) +{ + if (request.length() <= 8) + return; + + const char* pReq = 0; + const char* pURI = 0; + const char* pQuery = 0; + + switch (request[0]) { + case 'G': + if (request.indexOf("GET") == 0) + method = HTTP_GET; + break; + + case 'P': + if (request.indexOf("POST") == 0) + method = HTTP_POST; + break; + + case 'H': + if (request.indexOf("HEAD") == 0) + method = HTTP_HEAD; + break; + + default: + break; + } + + if (!method) return; + + char buffer[1024]; + int i = 0; + + // save the request line: + pReq = request.data(); + while (*pReq && *pReq != '\n') + buffer[i++] = *pReq++; + buffer[i] = 0; + + request_line = buffer; + i = 0; + + // find the URI: + pURI = request.data(); + while (*pURI && !isspace(*pURI)) + pURI++; + + while (*pURI && isspace(*pURI)) + pURI++; + + // copy the URI and find the query string: + while (*pURI && *pURI != '?' && !isspace(*pURI)) { + buffer[i++] = *pURI++; + } + + buffer[i] = 0; + uri = buffer; + pQuery = pURI; + + // parse the query string: + if (*pQuery == '?') { + pQuery++; + + while (*pQuery && !isspace(*pQuery)) { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) + name_buf[i++] = *pQuery++; + name_buf[i] = 0; + + if (*pQuery == '=') + pQuery++; + + i = 0; + while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) + value_buf[i++] = *pQuery++; + value_buf[i] = 0; + + if (*pQuery == '&') + pQuery++; + + HttpParam* param = new HttpParam(name_buf, DecodeParam(value_buf)); + if (param) + query.append(param); + } + } + + // get the headers: + const char* p = request.data(); + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + + while (*p && *p != '\r' && *p != '\n') { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*p && *p != ':') + name_buf[i++] = *p++; + name_buf[i] = 0; + + p++; // skip ':' + while (isspace(*p)) p++; // skip spaces + + i = 0; + while (*p && *p != '\r' && *p != '\n') // read to end of header line + value_buf[i++] = *p++; + value_buf[i] = 0; + + if (!_stricmp(name_buf, "Cookie")) { + ParseCookie(value_buf); + } + else { + HttpParam* param = new HttpParam(name_buf, value_buf); + if (param) + headers.append(param); + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + } + + if (method == HTTP_POST && *p) { + while (*p == '\n' || *p == '\r') + p++; + + content = *p; + pQuery = p; + + while (*pQuery && !isspace(*pQuery)) { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) + name_buf[i++] = *pQuery++; + name_buf[i] = 0; + + if (*pQuery == '=') + pQuery++; + + i = 0; + while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) + value_buf[i++] = *pQuery++; + value_buf[i] = 0; + + if (*pQuery == '&') + pQuery++; + + HttpParam* param = new HttpParam(name_buf, DecodeParam(value_buf)); + if (param) + query.append(param); + } + } +} + + +void +HttpRequest::ParseCookie(const char* param) +{ + const char* p = param; + + while (p && *p) { + while (isspace(*p)) p++; + + // just ignore reserved attributes + if (*p == '$') { + while (*p && !isspace(*p) && *p != ';') p++; + + if (*p == ';') + p++; + } + + // found a cookie! + else if (isalpha(*p)) { + char name[1024]; + char data[1024]; + + char* d = name; + while (*p && *p != '=') + *d++ = *p++; + *d = 0; + + if (*p == '=') + p++; + + if (*p == '"') + p++; + + d = data; + while (*p && *p != '"' && *p != ';') + *d++ = *p++; + *d = 0; + + if (*p == '"') + p++; + + if (*p == ';') + p++; + + HttpParam* param = new HttpParam(name, data); + if (param) + cookies.append(param); + } + + // this shouldn't happen - abandon the parse + else { + return; + } + } +} + + +Text +HttpRequest::GetParam(const char* name) +{ + ListIter iter = query; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + + +Text +HttpRequest::GetHeader(const char* name) +{ + ListIter iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + + +void +HttpRequest::SetHeader(const char* name, const char* value) +{ + ListIter iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new HttpParam(name, value); + if (param) + headers.append(param); +} + + +void +HttpRequest::AddHeader(const char* name, const char* value) +{ + HttpParam* param = new HttpParam(name, value); + if (param) + headers.append(param); +} + + +Text +HttpRequest::GetCookie(const char* name) +{ + ListIter iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + + +void +HttpRequest::SetCookie(const char* name, const char* value) +{ + ListIter iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new HttpParam(name, value); + if (param) + cookies.append(param); +} + + +void +HttpRequest::AddCookie(const char* name, const char* value) +{ + HttpParam* param = new HttpParam(name, value); + if (param) + cookies.append(param); +} + + +Text +HttpRequest::DecodeParam(const char* value) +{ + if (!value || !*value) return ""; + + int size = strlen(value); + char val = 0; + char code[4]; + char sbuf[256]; + char* lbuf = 0; + + char* dst = sbuf; + char* p = sbuf; + + if (size > 255) { + lbuf = new char[size+1]; + dst = lbuf; + p = lbuf; + } + + if (p) { + while (*value) { + switch (*value) { + default: *p++ = *value; break; + case '+': *p++ = ' '; break; + + case '%': + value++; + code[0] = *value++; + code[1] = *value; + code[2] = 0; + + val = (char) strtol(code, 0, 16); + *p++ = val; + break; + } + + value++; + } + + *p = 0; + } + + Text result = dst; + + if (lbuf) + delete [] lbuf; + + return result; +} + + +Text +HttpRequest::EncodeParam(const char* value) +{ + if (!value || !*value) return ""; + + int size = strlen(value); + char hex1 = 0; + char hex2 = 0; + + char sbuf[1024]; + char* lbuf = 0; + + char* dst = sbuf; + char* p = sbuf; + + if (size > 255) { + lbuf = new char[4*size+1]; + dst = lbuf; + p = lbuf; + } + + if (p) { + while (*value) { + switch (*value) { + default: *p++ = *value; break; + case ' ': *p++ = '+'; break; + + case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break; + case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break; + case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break; + case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break; + case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break; + case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break; + case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break; + case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break; + case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break; + case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break; + case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break; + case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break; + case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break; + case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break; + case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break; + case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break; + case '\n': break; + case '\r': break; + case '\t': break; + } + + value++; + } + + *p = 0; + } + + Text result = dst; + + if (lbuf) + delete [] lbuf; + + return result; +} + + +HttpRequest::operator Text() +{ + Text response = request_line.data(); + response += "\n"; + + for (int i = 0; i < headers.size(); i++) { + HttpParam* h = headers[i]; + response += h->name; + response += ": "; + response += h->value; + response += "\n"; + } + + for (int i = 0; i < cookies.size(); i++) { + HttpParam* c = cookies[i]; + response += "Cookie: "; + response += c->name; + response += "=\""; + response += c->value; + response += "\"\n"; + } + + response += "Connection: close\n\n"; + response += content; + + return response; +} diff --git a/NetEx/HttpRequest.h b/NetEx/HttpRequest.h new file mode 100644 index 0000000..10bfc77 --- /dev/null +++ b/NetEx/HttpRequest.h @@ -0,0 +1,76 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#ifndef HttpRequest_h +#define HttpRequest_h + +#include "HttpParam.h" +#include "List.h" +#include "NetAddr.h" + + +class HttpRequest +{ +public: + static const char* TYPENAME() { return "HttpRequest"; } + + enum METHOD { + HTTP_OPTIONS, + HTTP_GET, + HTTP_HEAD, + HTTP_POST, + HTTP_PUT, + HTTP_DELETE, + HTTP_TRACE, + HTTP_CONNECT + }; + + HttpRequest(const char* request=nullptr); + ~HttpRequest(); + + operator Text(); + + void ParseRequest(Text request); + void ParseCookie(const char* param); + + int Method() const { return method; } + Text URI() const { return uri; } + Text Content() const { return content; } + Text RequestLine() const { return request_line; } + + List& GetQuery() { return query; } + List& GetHeaders() { return headers; } + List& GetCookies() { return cookies; } + + NetAddr GetClientAddr() const { return client_addr; } + void SetClientAddr(const NetAddr& a) { client_addr = a; } + + Text GetParam(const char* name); + + Text GetHeader(const char* name); + void SetHeader(const char* name, const char* value); + void AddHeader(const char* name, const char* value); + Text GetCookie(const char* name); + void SetCookie(const char* name, const char* value); + void AddCookie(const char* name, const char* value); + + Text DecodeParam(const char* value); + static Text EncodeParam(const char* value); + +private: + int method; + Text uri; + Text content; + Text request_line; + NetAddr client_addr; + + List query; + List headers; + List cookies; +}; + + +#endif // HttpRequest_h diff --git a/NetEx/HttpResponse.cpp b/NetEx/HttpResponse.cpp new file mode 100644 index 0000000..de64f9d --- /dev/null +++ b/NetEx/HttpResponse.cpp @@ -0,0 +1,320 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#include "HttpResponse.h" + +#include +#include +#include + +#include "HttpParam.h" +#include "List.h" +#include "Text.h" + + +HttpResponse::HttpResponse(int stat, const char* data) : + status(stat), + content(data) +{ +} + + +HttpResponse::HttpResponse(const char* r) : + status(0), + content(r) +{ + if (r && *r) + ParseResponse(r); +} + + +HttpResponse::~HttpResponse() +{ + headers.destroy(); + cookies.destroy(); +} + + +HttpResponse::operator Text() +{ + Text response; + + switch (status) { + case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break; + case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break; + + case SC_OK : response = "HTTP/1.1 200 OK\n"; break; + case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break; + case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break; + case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break; + case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break; + case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break; + case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break; + + case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break; + case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break; + case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break; + case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break; + case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break; + case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break; + case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break; + + case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break; + case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break; + case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break; + case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break; + case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break; + case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break; + case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break; + case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break; + case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break; + case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break; + case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break; + case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break; + + default: + case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break; + case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break; + case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break; + case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break; + case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break; + case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break; + } + + SetHeader("Connection", "close"); + + char buffer[256]; + + if (content.length()) { + sprintf_s(buffer, "%d", content.length()); + SetHeader("Content-Length", buffer); + } + + for (int i = 0; i < cookies.size(); i++) { + HttpParam* cookie = cookies.at(i); + sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data()); + + AddHeader("Set-Cookie", buffer); + } + + for (int i = 0; i < headers.size(); i++) { + const HttpParam* p = headers.at(i); + sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data()); + response += buffer; + } + + response += "\n"; + response += content; + + return response; +} + + +Text +HttpResponse::GetHeader(const char* name) +{ + ListIter iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + + +void +HttpResponse::SetHeader(const char* name, const char* value) +{ + ListIter iter = headers; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new HttpParam(name, value); + if (param) + headers.append(param); +} + +void +HttpResponse::AddHeader(const char* name, const char* value) +{ + HttpParam* param = new HttpParam(name, value); + if (param) + headers.append(param); +} + + +Text +HttpResponse::GetCookie(const char* name) +{ + ListIter iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) + return p->value; + } + + return Text(); +} + +void +HttpResponse::SetCookie(const char* name, const char* value) +{ + ListIter iter = cookies; + while (++iter) { + HttpParam* p = iter.value(); + + if (p->name == name) { + p->value = value; + return; + } + } + + HttpParam* param = new HttpParam(name, value); + if (param) + cookies.append(param); +} + +void +HttpResponse::AddCookie(const char* name, const char* value) +{ + HttpParam* param = new HttpParam(name, value); + if (param) + cookies.append(param); +} + + +void +HttpResponse::SendRedirect(const char* url) +{ + status = SC_TEMPORARY_REDIRECT; + SetHeader("Location", url); +} + + +void +HttpResponse::ParseResponse(Text response) +{ + if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0) + return; + + const char* pStatus = response.data() + 9; + + sscanf_s(pStatus, "%d", &status); + if (!status) return; + + int i = 0; + + // get the headers: + const char* p = response.data(); + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + + while (*p && *p != '\r' && *p != '\n') { + char name_buf[1024]; + char value_buf[1024]; + + i = 0; + while (*p && *p != ':') + name_buf[i++] = *p++; + name_buf[i] = 0; + + p++; // skip ':' + while (isspace(*p)) p++; // skip spaces + + i = 0; + while (*p && *p != '\r' && *p != '\n') // read to end of header line + value_buf[i++] = *p++; + value_buf[i] = 0; + + if (!_stricmp(name_buf, "Set-Cookie")) { + ParseCookie(value_buf); + } + else { + HttpParam* param = new HttpParam(name_buf, value_buf); + if (param) + headers.append(param); + } + + while (*p && *p != '\n') + p++; + + if (*p == '\n') p++; + } + + if (*p == '\n') p++; + content = p; +} + + +void +HttpResponse::ParseCookie(const char* param) +{ + const char* p = param; + + while (p && *p) { + while (isspace(*p)) p++; + + // just ignore reserved attributes + if (*p == '$') { + while (*p && !isspace(*p) && *p != ';') p++; + + if (*p == ';') + p++; + } + + // found a cookie! + else if (isalpha(*p)) { + char name[1024]; + char data[1024]; + + char* d = name; + while (*p && *p != '=') + *d++ = *p++; + *d = 0; + + if (*p == '=') + p++; + + if (*p == '"') + p++; + + d = data; + while (*p && *p != '"' && *p != ';') + *d++ = *p++; + *d = 0; + + if (*p == '"') + p++; + + if (*p == ';') + p++; + + // ignore the version attribute + if (_stricmp(name, "version")) { + HttpParam* param = new HttpParam(name, data); + if (param) + cookies.append(param); + } + } + + // this shouldn't happen - abandon the parse + else { + return; + } + } +} diff --git a/NetEx/HttpResponse.h b/NetEx/HttpResponse.h new file mode 100644 index 0000000..cd53fcb --- /dev/null +++ b/NetEx/HttpResponse.h @@ -0,0 +1,99 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, Starshatter: The Open Source Project Contributors + Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors + Copyright (c) 1997-2006, Destroyer Studios LLC. +*/ + +#ifndef HttpResponse_h +#define HttpResponse_h + +#include "HttpParam.h" +#include "List.h" +#include "Text.h" + + +class HttpResponse +{ +public: + static const char* TYPENAME() { return "HttpResponse"; } + + enum STATUS { + SC_CONTINUE = 100, + SC_SWITCHING_PROTOCOLS = 101, + + SC_OK = 200, + SC_CREATED = 201, + SC_ACCEPTED = 202, + SC_NON_AUTHORITATIVE = 203, + SC_NO_CONTENT = 204, + SC_RESET_CONTENT = 205, + SC_PARTIAL_CONTENT = 206, + + SC_MULTIPLE_CHOICES = 300, + SC_MOVED_PERMANENTLY = 301, + SC_FOUND = 302, + SC_SEE_OTHER = 303, + SC_NOT_MODIFIED = 304, + SC_USE_PROXY = 305, + SC_TEMPORARY_REDIRECT = 307, + + SC_BAD_REQUEST = 400, + SC_UNAUTHORIZED = 401, + SC_PAYMENT_REQUIRED = 402, + SC_FORBIDDEN = 403, + SC_NOT_FOUND = 404, + SC_METHOD_NOT_ALLOWED = 405, + SC_NOT_ACCEPTABLE = 406, + SC_PROXY_AUTH_REQ = 407, + SC_REQUEST_TIME_OUT = 408, + SC_CONFLICT = 409, + SC_GONE = 410, + SC_LENGTH_REQUIRED = 411, + + SC_SERVER_ERROR = 500, + SC_NOT_IMPLEMENTED = 501, + SC_BAD_GATEWAY = 502, + SC_SERVICE_UNAVAILABLE = 503, + SC_GATEWAY_TIMEOUT = 504, + SC_VERSION_NOT_SUPPORTED= 505 + }; + + + HttpResponse(int status=500, const char* content=0); + HttpResponse(const char* response); + ~HttpResponse(); + + operator Text(); + + void ParseResponse(Text request); + void ParseCookie(const char* param); + + int Status() const { return status; } + void SetStatus(int s) { status = s; } + + Text Content() const { return content; } + void SetContent(Text t) { content = t; } + void AddContent(Text t) { content += t; } + + List& GetHeaders() { return headers; } + List& GetCookies() { return cookies; } + + Text GetHeader(const char* name); + void SetHeader(const char* name, const char* value); + void AddHeader(const char* name, const char* value); + Text GetCookie(const char* name); + void SetCookie(const char* name, const char* value); + void AddCookie(const char* name, const char* value); + + void SendRedirect(const char* url); + +private: + int status; + Text content; + + List headers; + List cookies; +}; + + +#endif // HttpResponse_h diff --git a/NetEx/HttpServer.cpp b/NetEx/HttpServer.cpp index 8098351..a7522e8 100644 --- a/NetEx/HttpServer.cpp +++ b/NetEx/HttpServer.cpp @@ -3,33 +3,39 @@ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors Copyright (c) 1997-2006, Destroyer Studios LLC. - AUTHOR: John DiCamillo + AUTHOR: John DiCamillo - OVERVIEW - ======== - Network Server Pump for HTTP Server + OVERVIEW + ======== + Network Server Pump for HTTP Server */ #include "HttpServer.h" -#include "NetLayer.h" -#include #include -#include +#include -// +-------------------------------------------------------------------+ +#include "HttpParam.h" +#include "HttpRequest.h" +#include "HttpResponse.h" +#include "List.h" +#include "NetAddr.h" +#include "NetServer.h" +#include "Text.h" -HttpServer::HttpServer(WORD port, int poolsize) - : NetServer(port, poolsize) + +HttpServer::HttpServer(WORD port, int poolsize) : + NetServer(port, poolsize) { http_server_name = "Generic HttpServer 1.0"; } + HttpServer::~HttpServer() -{ } +{ +} -// +--------------------------------------------------------------------+ Text HttpServer::ProcessRequest(Text msg, const NetAddr& addr) @@ -56,7 +62,6 @@ HttpServer::ProcessRequest(Text msg, const NetAddr& addr) return ErrorResponse(); } -// +--------------------------------------------------------------------+ Text HttpServer::GetServerName() @@ -64,13 +69,13 @@ HttpServer::GetServerName() return http_server_name; } + void HttpServer::SetServerName(const char* name) { http_server_name = name; } -// +--------------------------------------------------------------------+ Text HttpServer::DefaultResponse() @@ -82,6 +87,7 @@ HttpServer::DefaultResponse() return response; } + Text HttpServer::ErrorResponse() { @@ -100,7 +106,6 @@ HttpServer::ErrorResponse() return response; } -// +--------------------------------------------------------------------+ bool HttpServer::DoGet(HttpRequest& request, HttpResponse& response) @@ -179,7 +184,6 @@ HttpServer::DoGet(HttpRequest& request, HttpResponse& response) return true; } -// +--------------------------------------------------------------------+ bool HttpServer::DoPost(HttpRequest& request, HttpResponse& response) @@ -187,7 +191,6 @@ HttpServer::DoPost(HttpRequest& request, HttpResponse& response) return DoGet(request, response); } -// +--------------------------------------------------------------------+ bool HttpServer::DoHead(HttpRequest& request, HttpResponse& response) @@ -205,796 +208,3 @@ HttpServer::DoHead(HttpRequest& request, HttpResponse& response) return false; } - -// +--------------------------------------------------------------------+ -// +--------------------------------------------------------------------+ -// +--------------------------------------------------------------------+ - -HttpRequest::HttpRequest(const char* r) - : method(0) -{ - if (r && *r) - ParseRequest(r); -} - -HttpRequest::~HttpRequest() -{ - query.destroy(); - headers.destroy(); - cookies.destroy(); -} - -// +--------------------------------------------------------------------+ - -void -HttpRequest::ParseRequest(Text request) -{ - if (request.length() <= 8) - return; - - const char* pReq = 0; - const char* pURI = 0; - const char* pQuery = 0; - - switch (request[0]) { - case 'G': - if (request.indexOf("GET") == 0) - method = HTTP_GET; - break; - - case 'P': - if (request.indexOf("POST") == 0) - method = HTTP_POST; - break; - - case 'H': - if (request.indexOf("HEAD") == 0) - method = HTTP_HEAD; - break; - - default: - break; - } - - if (!method) return; - - char buffer[1024]; - int i = 0; - - // save the request line: - pReq = request.data(); - while (*pReq && *pReq != '\n') - buffer[i++] = *pReq++; - buffer[i] = 0; - - request_line = buffer; - i = 0; - - // find the URI: - pURI = request.data(); - while (*pURI && !isspace(*pURI)) - pURI++; - - while (*pURI && isspace(*pURI)) - pURI++; - - // copy the URI and find the query string: - while (*pURI && *pURI != '?' && !isspace(*pURI)) { - buffer[i++] = *pURI++; - } - - buffer[i] = 0; - uri = buffer; - pQuery = pURI; - - // parse the query string: - if (*pQuery == '?') { - pQuery++; - - while (*pQuery && !isspace(*pQuery)) { - char name_buf[1024]; - char value_buf[1024]; - - i = 0; - while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) - name_buf[i++] = *pQuery++; - name_buf[i] = 0; - - if (*pQuery == '=') - pQuery++; - - i = 0; - while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) - value_buf[i++] = *pQuery++; - value_buf[i] = 0; - - if (*pQuery == '&') - pQuery++; - - HttpParam* param = new HttpParam(name_buf, DecodeParam(value_buf)); - if (param) - query.append(param); - } - } - - // get the headers: - const char* p = request.data(); - while (*p && *p != '\n') - p++; - - if (*p == '\n') p++; - - while (*p && *p != '\r' && *p != '\n') { - char name_buf[1024]; - char value_buf[1024]; - - i = 0; - while (*p && *p != ':') - name_buf[i++] = *p++; - name_buf[i] = 0; - - p++; // skip ':' - while (isspace(*p)) p++; // skip spaces - - i = 0; - while (*p && *p != '\r' && *p != '\n') // read to end of header line - value_buf[i++] = *p++; - value_buf[i] = 0; - - if (!_stricmp(name_buf, "Cookie")) { - ParseCookie(value_buf); - } - else { - HttpParam* param = new HttpParam(name_buf, value_buf); - if (param) - headers.append(param); - } - - while (*p && *p != '\n') - p++; - - if (*p == '\n') p++; - } - - if (method == HTTP_POST && *p) { - while (*p == '\n' || *p == '\r') - p++; - - content = *p; - pQuery = p; - - while (*pQuery && !isspace(*pQuery)) { - char name_buf[1024]; - char value_buf[1024]; - - i = 0; - while (*pQuery && *pQuery != '=' && !isspace(*pQuery)) - name_buf[i++] = *pQuery++; - name_buf[i] = 0; - - if (*pQuery == '=') - pQuery++; - - i = 0; - while (*pQuery && *pQuery != '&' && !isspace(*pQuery)) - value_buf[i++] = *pQuery++; - value_buf[i] = 0; - - if (*pQuery == '&') - pQuery++; - - HttpParam* param = new HttpParam(name_buf, DecodeParam(value_buf)); - if (param) - query.append(param); - } - } -} - -void -HttpRequest::ParseCookie(const char* param) -{ - const char* p = param; - - while (p && *p) { - while (isspace(*p)) p++; - - // just ignore reserved attributes - if (*p == '$') { - while (*p && !isspace(*p) && *p != ';') p++; - - if (*p == ';') - p++; - } - - // found a cookie! - else if (isalpha(*p)) { - char name[1024]; - char data[1024]; - - char* d = name; - while (*p && *p != '=') - *d++ = *p++; - *d = 0; - - if (*p == '=') - p++; - - if (*p == '"') - p++; - - d = data; - while (*p && *p != '"' && *p != ';') - *d++ = *p++; - *d = 0; - - if (*p == '"') - p++; - - if (*p == ';') - p++; - - HttpParam* param = new HttpParam(name, data); - if (param) - cookies.append(param); - } - - // this shouldn't happen - abandon the parse - else { - return; - } - } -} - -// +--------------------------------------------------------------------+ - -Text -HttpRequest::GetParam(const char* name) -{ - ListIter iter = query; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) - return p->value; - } - - return Text(); -} - -// +--------------------------------------------------------------------+ - -Text -HttpRequest::GetHeader(const char* name) -{ - ListIter iter = headers; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) - return p->value; - } - - return Text(); -} - -void -HttpRequest::SetHeader(const char* name, const char* value) -{ - ListIter iter = headers; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) { - p->value = value; - return; - } - } - - HttpParam* param = new HttpParam(name, value); - if (param) - headers.append(param); -} - -void -HttpRequest::AddHeader(const char* name, const char* value) -{ - HttpParam* param = new HttpParam(name, value); - if (param) - headers.append(param); -} - -// +--------------------------------------------------------------------+ - -Text -HttpRequest::GetCookie(const char* name) -{ - ListIter iter = cookies; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) - return p->value; - } - - return Text(); -} - -void -HttpRequest::SetCookie(const char* name, const char* value) -{ - ListIter iter = cookies; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) { - p->value = value; - return; - } - } - - HttpParam* param = new HttpParam(name, value); - if (param) - cookies.append(param); -} - -void -HttpRequest::AddCookie(const char* name, const char* value) -{ - HttpParam* param = new HttpParam(name, value); - if (param) - cookies.append(param); -} - -// +--------------------------------------------------------------------+ - -Text -HttpRequest::DecodeParam(const char* value) -{ - if (!value || !*value) return ""; - - int size = strlen(value); - char val = 0; - char code[4]; - char sbuf[256]; - char* lbuf = 0; - - char* dst = sbuf; - char* p = sbuf; - - if (size > 255) { - lbuf = new char[size+1]; - dst = lbuf; - p = lbuf; - } - - if (p) { - while (*value) { - switch (*value) { - default: *p++ = *value; break; - case '+': *p++ = ' '; break; - - case '%': - value++; - code[0] = *value++; - code[1] = *value; - code[2] = 0; - - val = (char) strtol(code, 0, 16); - *p++ = val; - break; - } - - value++; - } - - *p = 0; - } - - Text result = dst; - - if (lbuf) - delete [] lbuf; - - return result; -} - -// +--------------------------------------------------------------------+ - -Text -HttpRequest::EncodeParam(const char* value) -{ - if (!value || !*value) return ""; - - int size = strlen(value); - char hex1 = 0; - char hex2 = 0; - - char sbuf[1024]; - char* lbuf = 0; - - char* dst = sbuf; - char* p = sbuf; - - if (size > 255) { - lbuf = new char[4*size+1]; - dst = lbuf; - p = lbuf; - } - - if (p) { - while (*value) { - switch (*value) { - default: *p++ = *value; break; - case ' ': *p++ = '+'; break; - - case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break; - case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break; - case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break; - case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break; - case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break; - case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break; - case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break; - case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break; - case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break; - case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break; - case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break; - case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break; - case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break; - case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break; - case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break; - case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break; - case '\n': break; - case '\r': break; - case '\t': break; - } - - value++; - } - - *p = 0; - } - - Text result = dst; - - if (lbuf) - delete [] lbuf; - - return result; -} - -// +--------------------------------------------------------------------+ - -HttpRequest::operator Text() -{ - Text response = request_line.data(); - response += "\n"; - - for (int i = 0; i < headers.size(); i++) { - HttpParam* h = headers[i]; - response += h->name; - response += ": "; - response += h->value; - response += "\n"; - } - - for (int i = 0; i < cookies.size(); i++) { - HttpParam* c = cookies[i]; - response += "Cookie: "; - response += c->name; - response += "=\""; - response += c->value; - response += "\"\n"; - } - - response += "Connection: close\n\n"; - response += content; - - return response; -} - -// +--------------------------------------------------------------------+ -// +--------------------------------------------------------------------+ -// +--------------------------------------------------------------------+ - -HttpResponse::HttpResponse(int stat, const char* data) - : status(stat), content(data) -{ } - -HttpResponse::HttpResponse(const char* r) - : status(0), content(r) -{ - if (r && *r) - ParseResponse(r); -} - -HttpResponse::~HttpResponse() -{ - headers.destroy(); - cookies.destroy(); -} - -// +--------------------------------------------------------------------+ - -HttpResponse::operator Text() -{ - Text response; - - switch (status) { - case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break; - case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break; - - case SC_OK : response = "HTTP/1.1 200 OK\n"; break; - case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break; - case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break; - case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break; - case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break; - case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break; - case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break; - - case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break; - case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break; - case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break; - case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break; - case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break; - case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break; - case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break; - - case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break; - case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break; - case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break; - case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break; - case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break; - case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break; - case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break; - case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break; - case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break; - case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break; - case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break; - case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break; - - default: - case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break; - case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break; - case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break; - case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break; - case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break; - case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break; - } - - SetHeader("Connection", "close"); - - char buffer[256]; - - if (content.length()) { - sprintf_s(buffer, "%d", content.length()); - SetHeader("Content-Length", buffer); - } - - for (int i = 0; i < cookies.size(); i++) { - HttpParam* cookie = cookies.at(i); - sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data()); - - AddHeader("Set-Cookie", buffer); - } - - for (int i = 0; i < headers.size(); i++) { - const HttpParam* p = headers.at(i); - sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data()); - response += buffer; - } - - response += "\n"; - response += content; - - return response; -} - -// +--------------------------------------------------------------------+ - -Text -HttpResponse::GetHeader(const char* name) -{ - ListIter iter = headers; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) - return p->value; - } - - return Text(); -} - -void -HttpResponse::SetHeader(const char* name, const char* value) -{ - ListIter iter = headers; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) { - p->value = value; - return; - } - } - - HttpParam* param = new HttpParam(name, value); - if (param) - headers.append(param); -} - -void -HttpResponse::AddHeader(const char* name, const char* value) -{ - HttpParam* param = new HttpParam(name, value); - if (param) - headers.append(param); -} - -// +--------------------------------------------------------------------+ - -Text -HttpResponse::GetCookie(const char* name) -{ - ListIter iter = cookies; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) - return p->value; - } - - return Text(); -} - -void -HttpResponse::SetCookie(const char* name, const char* value) -{ - ListIter iter = cookies; - while (++iter) { - HttpParam* p = iter.value(); - - if (p->name == name) { - p->value = value; - return; - } - } - - HttpParam* param = new HttpParam(name, value); - if (param) - cookies.append(param); -} - -void -HttpResponse::AddCookie(const char* name, const char* value) -{ - HttpParam* param = new HttpParam(name, value); - if (param) - cookies.append(param); -} - -// +--------------------------------------------------------------------+ - -void -HttpResponse::SendRedirect(const char* url) -{ - status = SC_TEMPORARY_REDIRECT; - SetHeader("Location", url); -} - -// +--------------------------------------------------------------------+ - -void -HttpResponse::ParseResponse(Text response) -{ - if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0) - return; - - const char* pStatus = response.data() + 9; - - sscanf_s(pStatus, "%d", &status); - if (!status) return; - - int i = 0; - - // get the headers: - const char* p = response.data(); - while (*p && *p != '\n') - p++; - - if (*p == '\n') p++; - - while (*p && *p != '\r' && *p != '\n') { - char name_buf[1024]; - char value_buf[1024]; - - i = 0; - while (*p && *p != ':') - name_buf[i++] = *p++; - name_buf[i] = 0; - - p++; // skip ':' - while (isspace(*p)) p++; // skip spaces - - i = 0; - while (*p && *p != '\r' && *p != '\n') // read to end of header line - value_buf[i++] = *p++; - value_buf[i] = 0; - - if (!_stricmp(name_buf, "Set-Cookie")) { - ParseCookie(value_buf); - } - else { - HttpParam* param = new HttpParam(name_buf, value_buf); - if (param) - headers.append(param); - } - - while (*p && *p != '\n') - p++; - - if (*p == '\n') p++; - } - - if (*p == '\n') p++; - content = p; -} - -void -HttpResponse::ParseCookie(const char* param) -{ - const char* p = param; - - while (p && *p) { - while (isspace(*p)) p++; - - // just ignore reserved attributes - if (*p == '$') { - while (*p && !isspace(*p) && *p != ';') p++; - - if (*p == ';') - p++; - } - - // found a cookie! - else if (isalpha(*p)) { - char name[1024]; - char data[1024]; - - char* d = name; - while (*p && *p != '=') - *d++ = *p++; - *d = 0; - - if (*p == '=') - p++; - - if (*p == '"') - p++; - - d = data; - while (*p && *p != '"' && *p != ';') - *d++ = *p++; - *d = 0; - - if (*p == '"') - p++; - - if (*p == ';') - p++; - - // ignore the version attribute - if (_stricmp(name, "version")) { - HttpParam* param = new HttpParam(name, data); - if (param) - cookies.append(param); - } - } - - // this shouldn't happen - abandon the parse - else { - return; - } - } -} - diff --git a/NetEx/HttpServer.h b/NetEx/HttpServer.h index a4b906b..8bac7ab 100644 --- a/NetEx/HttpServer.h +++ b/NetEx/HttpServer.h @@ -3,27 +3,25 @@ Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors Copyright (c) 1997-2006, Destroyer Studios LLC. - AUTHOR: John DiCamillo + AUTHOR: John DiCamillo - OVERVIEW - ======== - Network Server Pump for HTTP Server + OVERVIEW + ======== + Network Server Pump for HTTP Server */ - #ifndef HttpServer_h #define HttpServer_h -#include "NetServer.h" - -// +-------------------------------------------------------------------+ +#include -class HttpParam; -class HttpRequest; -class HttpResponse; +#include "HttpRequest.h" +#include "HttpResponse.h" +#include "NetAddr.h" +#include "NetServer.h" +#include "Text.h" -// +-------------------------------------------------------------------+ class HttpServer : public NetServer { @@ -50,167 +48,5 @@ protected: Text http_server_name; }; -// +-------------------------------------------------------------------+ - -class HttpParam -{ -public: - static const char* TYPENAME() { return "HttpParam"; } - - HttpParam(const char* n, const char* v) : name(n), value(v) { } - - int operator == (const HttpParam& p) const { return name == p.name; } - - Text name; - Text value; -}; - -// +-------------------------------------------------------------------+ - -class HttpRequest -{ -public: - static const char* TYPENAME() { return "HttpRequest"; } - - enum METHOD { - HTTP_OPTIONS, - HTTP_GET, - HTTP_HEAD, - HTTP_POST, - HTTP_PUT, - HTTP_DELETE, - HTTP_TRACE, - HTTP_CONNECT - }; - - HttpRequest(const char* request=0); - ~HttpRequest(); - - operator Text(); - - void ParseRequest(Text request); - void ParseCookie(const char* param); - - int Method() const { return method; } - Text URI() const { return uri; } - Text Content() const { return content; } - Text RequestLine() const { return request_line; } - - List& GetQuery() { return query; } - List& GetHeaders() { return headers; } - List& GetCookies() { return cookies; } - - NetAddr GetClientAddr() const { return client_addr; } - void SetClientAddr(const NetAddr& a) { client_addr = a; } - - Text GetParam(const char* name); - - Text GetHeader(const char* name); - void SetHeader(const char* name, const char* value); - void AddHeader(const char* name, const char* value); - Text GetCookie(const char* name); - void SetCookie(const char* name, const char* value); - void AddCookie(const char* name, const char* value); - - Text DecodeParam(const char* value); - static Text EncodeParam(const char* value); - -private: - int method; - Text uri; - Text content; - Text request_line; - NetAddr client_addr; - - List query; - List headers; - List cookies; -}; - -// +-------------------------------------------------------------------+ - -class HttpResponse -{ -public: - static const char* TYPENAME() { return "HttpResponse"; } - - enum STATUS { - SC_CONTINUE = 100, - SC_SWITCHING_PROTOCOLS = 101, - - SC_OK = 200, - SC_CREATED = 201, - SC_ACCEPTED = 202, - SC_NON_AUTHORITATIVE = 203, - SC_NO_CONTENT = 204, - SC_RESET_CONTENT = 205, - SC_PARTIAL_CONTENT = 206, - - SC_MULTIPLE_CHOICES = 300, - SC_MOVED_PERMANENTLY = 301, - SC_FOUND = 302, - SC_SEE_OTHER = 303, - SC_NOT_MODIFIED = 304, - SC_USE_PROXY = 305, - SC_TEMPORARY_REDIRECT = 307, - - SC_BAD_REQUEST = 400, - SC_UNAUTHORIZED = 401, - SC_PAYMENT_REQUIRED = 402, - SC_FORBIDDEN = 403, - SC_NOT_FOUND = 404, - SC_METHOD_NOT_ALLOWED = 405, - SC_NOT_ACCEPTABLE = 406, - SC_PROXY_AUTH_REQ = 407, - SC_REQUEST_TIME_OUT = 408, - SC_CONFLICT = 409, - SC_GONE = 410, - SC_LENGTH_REQUIRED = 411, - - SC_SERVER_ERROR = 500, - SC_NOT_IMPLEMENTED = 501, - SC_BAD_GATEWAY = 502, - SC_SERVICE_UNAVAILABLE = 503, - SC_GATEWAY_TIMEOUT = 504, - SC_VERSION_NOT_SUPPORTED= 505 - }; - - - HttpResponse(int status=500, const char* content=0); - HttpResponse(const char* response); - ~HttpResponse(); - - operator Text(); - - void ParseResponse(Text request); - void ParseCookie(const char* param); - - int Status() const { return status; } - void SetStatus(int s) { status = s; } - - Text Content() const { return content; } - void SetContent(Text t) { content = t; } - void AddContent(Text t) { content += t; } - - List& GetHeaders() { return headers; } - List& GetCookies() { return cookies; } - - Text GetHeader(const char* name); - void SetHeader(const char* name, const char* value); - void AddHeader(const char* name, const char* value); - Text GetCookie(const char* name); - void SetCookie(const char* name, const char* value); - void AddCookie(const char* name, const char* value); - - void SendRedirect(const char* url); - -private: - int status; - Text content; - - List headers; - List cookies; -}; - #endif // HttpServer_h -- cgit v1.1