summaryrefslogtreecommitdiffhomepage
path: root/NetEx
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-03-29 22:40:57 +0200
committerAki <please@ignore.pl>2022-03-29 22:40:57 +0200
commit6204e62c69c1a05d3beddd0c7397b3f54e576d74 (patch)
tree6dfc5ef3c017942fd1a9d980893fe1c0c0ebd427 /NetEx
parented2b908b7d88bcb5730ef74ae97020b683da51ae (diff)
downloadstarshatter-6204e62c69c1a05d3beddd0c7397b3f54e576d74.zip
starshatter-6204e62c69c1a05d3beddd0c7397b3f54e576d74.tar.gz
starshatter-6204e62c69c1a05d3beddd0c7397b3f54e576d74.tar.bz2
Split Param, Response and Request from HttpServer files
Diffstat (limited to 'NetEx')
-rw-r--r--NetEx/CMakeLists.txt3
-rw-r--r--NetEx/HttpParam.cpp21
-rw-r--r--NetEx/HttpParam.h27
-rw-r--r--NetEx/HttpRequest.cpp497
-rw-r--r--NetEx/HttpRequest.h76
-rw-r--r--NetEx/HttpResponse.cpp320
-rw-r--r--NetEx/HttpResponse.h99
-rw-r--r--NetEx/HttpServer.cpp830
-rw-r--r--NetEx/HttpServer.h184
9 files changed, 1073 insertions, 984 deletions
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 <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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<HttpParam> iter = query;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+
+Text
+HttpRequest::GetHeader(const char* name)
+{
+ ListIter<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam>& GetQuery() { return query; }
+ List<HttpParam>& GetHeaders() { return headers; }
+ List<HttpParam>& 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<HttpParam> query;
+ List<HttpParam> headers;
+ List<HttpParam> 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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam>& GetHeaders() { return headers; }
+ List<HttpParam>& 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<HttpParam> headers;
+ List<HttpParam> 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 <stdlib.h>
#include <stdio.h>
-#include <ctype.h>
+#include <windows.h>
-// +-------------------------------------------------------------------+
+#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<HttpParam> iter = query;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::GetHeader(const char* name)
-{
- ListIter<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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<HttpParam> 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 <windows.h>
-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<HttpParam>& GetQuery() { return query; }
- List<HttpParam>& GetHeaders() { return headers; }
- List<HttpParam>& 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<HttpParam> query;
- List<HttpParam> headers;
- List<HttpParam> 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<HttpParam>& GetHeaders() { return headers; }
- List<HttpParam>& 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<HttpParam> headers;
- List<HttpParam> cookies;
-};
-
#endif // HttpServer_h