aboutsummaryrefslogtreecommitdiff
path: root/Src/replicant/jnetlib/httpserv.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/jnetlib/httpserv.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/replicant/jnetlib/httpserv.cpp')
-rw-r--r--Src/replicant/jnetlib/httpserv.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/Src/replicant/jnetlib/httpserv.cpp b/Src/replicant/jnetlib/httpserv.cpp
new file mode 100644
index 00000000..4a129e9b
--- /dev/null
+++ b/Src/replicant/jnetlib/httpserv.cpp
@@ -0,0 +1,234 @@
+/*
+** JNetLib
+** Copyright (C) 2001 Nullsoft, Inc.
+** Author: Justin Frankel
+** File: httpserv.cpp - JNL HTTP GET/POST serving implementation
+** License: see jnetlib.h
+**
+** This class just manages the http reply/sending, not where the data
+** comes from, etc.
+*/
+
+#include "netinc.h"
+#include "util.h"
+
+#include "httpserv.h"
+
+/*
+ States for m_state:
+ -1 error (connection closed, etc)
+ 0 not read request yet.
+ 1 reading headers
+ 2 headers read, have not sent reply
+ 3 sent reply
+ 4 closed
+*/
+
+JNL_HTTPServ::JNL_HTTPServ(JNL_Connection *con)
+{
+ m_con=con;
+ m_state=0;
+ m_reply_headers=0;
+ m_reply_string=0;
+ m_recv_request=0;
+ m_errstr=0;
+ m_reply_ready=0;
+ m_method = 0;
+ http_ver = 0;
+ keep_alive = 0;
+}
+
+JNL_HTTPServ::~JNL_HTTPServ()
+{
+ free(m_recv_request);
+ free(m_reply_string);
+ free(m_reply_headers);
+ free(m_errstr);
+ free(m_method);
+ m_con->Release();
+}
+
+static size_t strlen_whitespace(const char *str)
+{
+ size_t size=0;
+ while (str && *str && *str != ' ' && *str != '\r' && *str!='\n')
+ {
+ str++;
+ size++;
+ }
+ return size;
+}
+
+int JNL_HTTPServ::run()
+{ // returns: < 0 on error, 0 on connection close, 1 if reading request, 2 if reply not sent, 3 if reply sent, sending data.
+ int cnt=0;
+run_again:
+ m_con->run();
+ if (m_con->get_state()==JNL_Connection::STATE_ERROR)
+ {
+ seterrstr(m_con->get_errstr());
+ return -1;
+ }
+
+ if (m_con->get_state()==JNL_Connection::STATE_CLOSED)
+ return 4;
+
+ if (m_state == 0)
+ {
+ if (m_con->recv_lines_available()>0)
+ {
+ char *buf=(char*)malloc(m_con->recv_bytes_available()-1);
+ m_con->recv_line(buf,m_con->recv_bytes_available()-1);
+ free(m_recv_request);
+ m_recv_request=(char*)malloc(strlen(buf)+2);
+ strcpy(m_recv_request,buf);
+ m_recv_request[strlen(m_recv_request)+1]=0;
+ free(buf);
+ buf=m_recv_request;
+ while (buf && *buf) buf++;
+ while (buf >= m_recv_request && *buf != ' ') buf--;
+ if (strncmp(buf+1,"HTTP",4))// || strncmp(m_recv_request,"GET ",3))
+ {
+ seterrstr("malformed HTTP request");
+ m_state=-1;
+ }
+ else
+ {
+ http_ver = atoi(buf+8);
+
+ size_t method_len = strlen_whitespace(m_recv_request);
+ m_method = (char *)malloc(method_len + 1);
+ memcpy(m_method, m_recv_request, method_len);
+ m_method[method_len]=0;
+
+ m_state=1;
+ cnt=0;
+ if (buf >= m_recv_request) buf[0]=buf[1]=0;
+
+ buf=strstr(m_recv_request,"?");
+ if (buf)
+ {
+ *buf++=0; // change &'s into 0s now.
+ char *t=buf;
+ int stat=1;
+ while (t && *t)
+ {
+ if (*t == '&' && !stat) { stat=1; *t=0; }
+ else stat=0;
+ t++;
+ }
+ }
+ }
+ }
+ else if (!cnt++) goto run_again;
+ }
+ if (m_state == 1)
+ {
+ if (!cnt++ && m_con->recv_lines_available()<1) goto run_again;
+ while (m_con->recv_lines_available()>0)
+ {
+ char buf[4096] = {0};
+ m_con->recv_line(buf,4096);
+ if (!buf[0])
+ {
+ m_state=2;
+ break;
+ }
+ recvheaders.Add(buf);
+ }
+ }
+ if (m_state == 2)
+ {
+ if (m_reply_ready)
+ {
+ // send reply
+ m_con->send_string((char*)(m_reply_string?m_reply_string:"HTTP/1.1 200 OK"));
+ m_con->send_string("\r\n");
+ if (m_reply_headers) m_con->send_string(m_reply_headers);
+ m_con->send_string("\r\n");
+ m_state=3;
+ }
+ }
+ if (m_state == 3)
+ {
+ // nothing.
+ }
+
+ return m_state;
+}
+
+const char *JNL_HTTPServ::get_request_file()
+{
+ // file portion of http request
+ if (!m_recv_request) return NULL;
+ char *t=m_recv_request;
+ while (t && *t && *t != ' ') t++;
+ if (!t || !*t) return NULL;
+ while (t && *t && *t == ' ') t++;
+ return t;
+}
+
+const char *JNL_HTTPServ::get_request_parm(const char *parmname) // parameter portion (after ?)
+{
+ const char *t=m_recv_request;
+ while (t && *t) t++;
+ if (t) t++;
+ while (t && *t)
+ {
+ while (t && *t && *t == '&') t++;
+ if (!_strnicmp(t,parmname,strlen(parmname)) && t[strlen(parmname)] == '=')
+ {
+ return t+strlen(parmname)+1;
+ }
+ t+=strlen(t)+1;
+ }
+ return NULL;
+}
+
+const char *JNL_HTTPServ::getheader(const char *headername)
+{
+ return recvheaders.GetHeader(headername);
+}
+
+void JNL_HTTPServ::set_reply_string(const char *reply_string) // should be HTTP/1.1 OK or the like
+{
+ free(m_reply_string);
+ m_reply_string=(char*)malloc(strlen(reply_string)+1);
+ strcpy(m_reply_string,reply_string);
+}
+
+void JNL_HTTPServ::add_reply_header(const char *header) // "Connection: close" for example
+{
+ // if they've specified a content-length, then we can keep alive an HTTP/1.1 connection
+ if (!keep_alive && http_ver == 1 && !_strnicmp(header, "Content-Length", 14))
+ keep_alive = 1;
+
+ if (m_reply_headers)
+ {
+ char *tmp=(char*)malloc(strlen(m_reply_headers)+strlen(header)+3);
+ strcpy(tmp,m_reply_headers);
+ strcat(tmp,header);
+ strcat(tmp,"\r\n");
+ free(m_reply_headers);
+ m_reply_headers=tmp;
+ }
+ else
+ {
+ m_reply_headers=(char*)malloc(strlen(header)+3);
+ strcpy(m_reply_headers,header);
+ strcat(m_reply_headers,"\r\n");
+ }
+}
+
+void JNL_HTTPServ::reset()
+{
+ free(m_recv_request); m_recv_request = 0;
+ free(m_reply_string); m_reply_string = 0;
+ free(m_reply_headers); m_reply_headers = 0;
+ free(m_errstr); m_errstr = 0;
+ free(m_method); m_method =0;
+ m_reply_ready=0;
+ m_state = 0;
+ keep_alive = 0;
+}
+