add oversampler
This commit is contained in:
262
oversampling/WDL/jnetlib/httpserv.cpp
Normal file
262
oversampling/WDL/jnetlib/httpserv.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
** JNetLib
|
||||
** Copyright (C) 2008 Cockos Inc
|
||||
** 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_IConnection *con)
|
||||
{
|
||||
m_usechunk = false;
|
||||
m_keepalive = true;
|
||||
m_con=con;
|
||||
m_state=0;
|
||||
m_reply_ready=0;
|
||||
}
|
||||
|
||||
JNL_HTTPServ::~JNL_HTTPServ()
|
||||
{
|
||||
delete m_con;
|
||||
}
|
||||
|
||||
void JNL_HTTPServ::write_bytes(const char *bytes, int length)
|
||||
{
|
||||
if (m_usechunk)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf,"%x\r\n",length);
|
||||
m_con->send_string(buf);
|
||||
}
|
||||
m_con->send(bytes,length);
|
||||
if (m_usechunk) m_con->send_string("\r\n");
|
||||
}
|
||||
|
||||
bool JNL_HTTPServ::want_keepalive_reset()
|
||||
{
|
||||
if (m_state >= 2 && m_con && m_con->get_state() == JNL_Connection::STATE_CONNECTED)
|
||||
{
|
||||
m_usechunk = false;
|
||||
m_state = 0;
|
||||
m_reply_ready = 0;
|
||||
m_errstr.Set("");
|
||||
m_reply_headers.Set("");
|
||||
m_reply_string.Set("");
|
||||
m_recvheaders.Clear();
|
||||
m_recv_request.Resize(0,false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int reqlen = m_con->recv_get_linelen();
|
||||
if (reqlen>0)
|
||||
{
|
||||
if (!m_recv_request.ResizeOK(reqlen+2,false))
|
||||
{
|
||||
seterrstr("malloc fail");
|
||||
return -1;
|
||||
}
|
||||
|
||||
reqlen = m_con->recv_bytes(m_recv_request.Get(),reqlen);
|
||||
char *buf = m_recv_request.Get() + reqlen;
|
||||
*buf=0;
|
||||
while (buf > m_recv_request.Get() && (buf[-1] == '\r' || buf[-1]=='\n')) *--buf=0;
|
||||
const char *endptr = buf;
|
||||
while (buf >= m_recv_request.Get() && *buf != ' ') buf--;
|
||||
|
||||
if (buf < m_recv_request.Get() || strncmp(buf+1,"HTTP",4) || strncmp(m_recv_request.Get(),"GET ",4))
|
||||
{
|
||||
seterrstr("malformed HTTP request");
|
||||
m_state=-1;
|
||||
buf=m_recv_request.Get();
|
||||
buf[0]=buf[1]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endptr[-1]=='0') m_keepalive = false; // old http 1.0
|
||||
m_state=1;
|
||||
cnt=0;
|
||||
buf[0]=buf[1]=0;
|
||||
|
||||
buf=strstr(m_recv_request.Get(),"?");
|
||||
if (buf)
|
||||
{
|
||||
*buf++=0; // change &'s into 0s now.
|
||||
char *t=buf;
|
||||
int stat=1;
|
||||
while (*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_get_linelen()>0)
|
||||
{
|
||||
char buf[4096];
|
||||
buf[0]=0;
|
||||
m_con->recv_line(buf,4096);
|
||||
if (!buf[0]) { m_state=2; break; }
|
||||
|
||||
if (!strnicmp(buf,"Connection:",11))
|
||||
{
|
||||
const char *p=buf+11;
|
||||
while (*p && strnicmp(p,"close",5)) p++;
|
||||
if (*p) m_keepalive = false;
|
||||
}
|
||||
|
||||
if (m_recvheaders.GetSize()) m_recvheaders.Add(NULL,-1); // remove doublenull
|
||||
m_recvheaders.Add(buf,strlen(buf)+1);
|
||||
m_recvheaders.Add("",1);
|
||||
}
|
||||
}
|
||||
if (m_state == 2)
|
||||
{
|
||||
if (m_reply_ready)
|
||||
{
|
||||
// send reply
|
||||
m_con->send_string((char*)(m_reply_string.GetLength()?m_reply_string.Get():"HTTP/1.1 200 OK"));
|
||||
m_con->send_string("\r\n");
|
||||
if (m_reply_headers.GetLength()) m_con->send_string(m_reply_headers.Get());
|
||||
if (m_keepalive)
|
||||
{
|
||||
const char *p = m_reply_headers.Get();
|
||||
bool had_cl=false,had_con=false;
|
||||
while (*p && (!had_cl || !had_con))
|
||||
{
|
||||
if (!strnicmp(p,"Content-Length:",15)) had_cl=true;
|
||||
else if (!strnicmp(p,"Connection:",11)) had_con=true;
|
||||
|
||||
while (*p && *p != '\r' && *p != '\n') p++;
|
||||
while (*p == '\r' || *p == '\n') p++;
|
||||
}
|
||||
if (!had_con) m_con->send_string("Connection: keep-alive\r\n");
|
||||
if (!had_cl)
|
||||
{
|
||||
m_usechunk = true;
|
||||
m_con->send_string("Transfer-Encoding: chunked\r\n");
|
||||
}
|
||||
}
|
||||
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
|
||||
char *t=m_recv_request.Get();
|
||||
if (!t) return NULL;
|
||||
|
||||
while (*t != ' ' && *t) t++;
|
||||
if (!*t) return NULL;
|
||||
while (*t == ' ') t++;
|
||||
return t;
|
||||
}
|
||||
|
||||
const char *JNL_HTTPServ::get_request_parm(const char *parmname) // parameter portion (after ?)
|
||||
{
|
||||
const char *t=m_recv_request.Get();
|
||||
if (!t) return NULL;
|
||||
|
||||
while (*t) t++;
|
||||
t++;
|
||||
while (*t)
|
||||
{
|
||||
while (*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)
|
||||
{
|
||||
const char *ret=NULL;
|
||||
if (strlen(headername)<1||!m_recvheaders.Available()) return NULL;
|
||||
const char *p=m_recvheaders.Get();
|
||||
const int hdrlen = (int) strlen(headername);
|
||||
while (*p)
|
||||
{
|
||||
if (!strnicmp(headername,p,hdrlen) && p[hdrlen] == ':')
|
||||
{
|
||||
ret=p+hdrlen+1;
|
||||
while (*ret == ' ') ret++;
|
||||
break;
|
||||
}
|
||||
while (*p) p++;
|
||||
p++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void JNL_HTTPServ::set_reply_string(const char *reply_string) // should be HTTP/1.1 OK or the like
|
||||
{
|
||||
m_reply_string.Set(reply_string);
|
||||
}
|
||||
|
||||
void JNL_HTTPServ::set_reply_size(int sz) // if set, size will also add keep-alive etc
|
||||
{
|
||||
if (sz>=0)
|
||||
{
|
||||
char buf[512];
|
||||
sprintf(buf,"Content-length: %d",sz);
|
||||
set_reply_header(buf);
|
||||
}
|
||||
}
|
||||
void JNL_HTTPServ::set_reply_header(const char *header) // "Connection: close" for example
|
||||
{
|
||||
m_reply_headers.Append(header);
|
||||
m_reply_headers.Append("\r\n");
|
||||
}
|
||||
Reference in New Issue
Block a user