Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/httpcgi.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ struct httpc {
double end; /* 38 end time in seconds */

UCHAR rdw; /* 40 RDW option */
UCHAR unused; /* 41 available */
UCHAR chunked; /* 41 chunked transfer encoding */
short resp; /* 42 response code */
CRED *cred; /* 44 client credential */
UFS *ufs; /* 48 UFS handle (opaque) */
Expand All @@ -125,7 +125,7 @@ struct httpc {
UCHAR ssi; /* 50 Server Side Include enable */
UCHAR ssilevel; /* 51 SSI processing level */
#define SSI_LEVEL_MAX 10 /* ... max SSI processing level */
UCHAR unused1; /* 52 available */
UCHAR content_length_set; /* 52 Content-Length was sent */
UCHAR unused2; /* 53 available */
unsigned unused3; /* 54 available */

Expand Down
4 changes: 2 additions & 2 deletions include/httpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ struct httpc {
double end; /* 38 end time in seconds */

UCHAR rdw; /* 40 RDW option */
UCHAR unused; /* 41 available */
UCHAR chunked; /* 41 chunked transfer encoding */
short resp; /* 42 response code */
CRED *cred; /* 44 client credential */
UFS *ufs; /* 48 UFS handle */
Expand All @@ -209,7 +209,7 @@ struct httpc {
UCHAR ssi; /* 50 Server Side Include enable */
UCHAR ssilevel; /* 51 SSI processing level */
#define SSI_LEVEL_MAX 10 /* ... max SSI processing levele*/
UCHAR unused1; /* 52 available */
UCHAR content_length_set; /* 52 Content-Length was sent */
UCHAR unused2; /* 53 available */
unsigned unused3; /* 54 available */

Expand Down
13 changes: 13 additions & 0 deletions src/httpdone.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ httpdone(HTTPC *httpc)
ufs_fclose(&httpc->ufp);
}

/* send terminating chunk for chunked transfer encoding */
if (httpc->chunked) {
/* "0\r\n\r\n" in ASCII — disable framing first */
UCHAR term[5];
httpc->chunked = 0;
term[0] = 0x30; /* '0' */
term[1] = 0x0D; /* CR */
term[2] = 0x0A; /* LF */
term[3] = 0x0D; /* CR */
term[4] = 0x0A; /* LF */
http_send(httpc, term, 5);
}

httpsecs(&httpc->end);

quit:
Expand Down
49 changes: 47 additions & 2 deletions src/httpget.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ httpget(HTTPC *httpc)
{
int rc = 0;
UCHAR *path;
UCHAR *open_path = NULL;
const HTTPM *mime;
FILE *fp;
int len;
Expand All @@ -38,6 +39,7 @@ httpget(HTTPC *httpc)

/* try to open path from UFS */
mime = http_mime(path);
open_path = path;
fp = http_open(httpc, path, mime);
if (fp || httpc->ufp) goto okay;

Expand All @@ -47,11 +49,13 @@ httpget(HTTPC *httpc)
memcpy(buf, path, len);
strcpy(&buf[len], "index.html");
mime = http_mime(buf);
open_path = buf;
fp = http_open(httpc, buf, mime);
if (fp || httpc->ufp) goto okay;

strcpy(&buf[len], "default.html");
mime = http_mime(buf);
open_path = buf;
fp = http_open(httpc, buf, mime);
if (fp || httpc->ufp) goto okay;
}
Expand Down Expand Up @@ -80,8 +84,49 @@ httpget(HTTPC *httpc)
#endif
rc = http_printf(httpc, "Content-Type: %s\r\n", mime->type);
if (rc) goto die;
rc = http_printf(httpc, "\r\n");
if (rc) goto die;

/* Content-Length for static UFS files, chunked for SSI */
if (!httpc->ssi && httpc->ufp) {
UFS *ufs = http_get_ufs(httpc);
if (ufs) {
UFSDLIST st;
UCHAR ufspath[256];
const char *dr = httpc->httpd->docroot;
if (dr[0]) {
snprintf((char *)ufspath, sizeof(ufspath), "%s%s",
dr, open_path);
} else {
snprintf((char *)ufspath, sizeof(ufspath), "%s", open_path);
}
if (ufs_stat(ufs, (const char *)ufspath, &st) == 0
&& st.filesize > 0) {
rc = http_printf(httpc, "Content-Length: %u\r\n",
st.filesize);
if (rc) goto die;
httpc->content_length_set = 1;
}
}
}

/* chunked transfer encoding only for HTTP/1.1 clients */
{
int use_chunked = 0;
if (!httpc->content_length_set) {
UCHAR *ver = http_get_env(httpc, "REQUEST_VERSION");
if (ver && http_cmp(ver, "HTTP/1.1") == 0) {
rc = http_printf(httpc, "Transfer-Encoding: chunked\r\n");
if (rc) goto die;
use_chunked = 1;
}
/* HTTP/1.0: no chunked, body delimited by Connection: close */
}

rc = http_printf(httpc, "\r\n");
if (rc) goto die;

/* enable chunk framing AFTER header-ending CRLF is sent */
httpc->chunked = use_chunked;
}

/* indicate type of document being sent */
if (mime->binary) {
Expand Down
15 changes: 15 additions & 0 deletions src/httpin.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ int http_in(HTTPC *httpc)
if (http_set_http_env(httpc, buf, p)) goto failed;
} while(rc > 0);

/* HTTP/1.1 requires a Host header */
{
UCHAR *ver = http_get_env(httpc, "REQUEST_VERSION");
if (ver && http_cmp(ver, "HTTP/1.1") == 0) {
UCHAR *host = http_get_env(httpc, "HTTP_HOST");
if (!host || !host[0]) {
http_resp(httpc, 400);
http_printf(httpc, "Content-Type: text/plain\r\n\r\n");
http_printf(httpc, "400 Bad Request: Missing Host header\r\n");
httpc->state = CSTATE_DONE;
goto quit;
}
}
}

/* next step will parse and do any additional processing */
rc = 0;
httpc->state = CSTATE_PARSE;
Expand Down
2 changes: 1 addition & 1 deletion src/httppars.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ httppars(HTTPC *httpc)
if (http_set_env(httpc, "SERVER_PORT", tmp)) goto failed;
}

if (http_set_env(httpc, "SERVER_PROTOCOL", "HTTP/1.0")) goto failed;
if (http_set_env(httpc, "SERVER_PROTOCOL", "HTTP/1.1")) goto failed;

sprintf(tmp, "HTTPD/%s", httpc->httpd->version);
if (http_set_env(httpc, "SERVER_SOFTWARE", tmp)) goto failed;
Expand Down
2 changes: 2 additions & 0 deletions src/httprese.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ httprese(HTTPC *httpc)
httpc->sent = 0;
httpc->subtype = 0;
httpc->substate = 0;
httpc->chunked = 0;
httpc->content_length_set = 0;
httpc->start = 0.0;
httpc->end = 0.0;
memset(httpc->buf, 0, CBUFSIZE);
Expand Down
14 changes: 13 additions & 1 deletion src/httpresp.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@ httpresp(HTTPC *httpc, int resp)

httpc->resp = resp;

rc = http_printf(httpc, "HTTP/1.0 %s\r\n", p);
/* match response version to client request version */
{
UCHAR *ver = http_get_env(httpc, "REQUEST_VERSION");
if (ver && http_cmp(ver, "HTTP/1.1") == 0) {
rc = http_printf(httpc, "HTTP/1.1 %s\r\n", p);
} else {
rc = http_printf(httpc, "HTTP/1.0 %s\r\n", p);
}
}
if (rc) goto quit;

now = time64(NULL);
Expand All @@ -68,6 +76,10 @@ httpresp(HTTPC *httpc, int resp)
if (rc) goto quit;
}

/* HTTP/1.1: always close for now (keep-alive planned) */
rc = http_printf(httpc, "Connection: close\r\n");
if (rc) goto quit;

quit:
http_exit("httpresp(), rc=%d\n", rc);
return rc;
Expand Down
74 changes: 43 additions & 31 deletions src/httpsend.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,74 @@
*/
#include "httpd.h"

extern int
httpsend(HTTPC *httpc, const UCHAR *buf, int len)
/* send_raw() - send raw bytes to socket without chunk framing */
static int
send_raw(HTTPC *httpc, const UCHAR *buf, int len)
{
int rc;
int pos = 0;

#if 0
wtof("httpsend(%08X,%08X,%d)", httpc, buf, len);
#endif

/* send data to socket */
for(pos=0; pos < len; pos+=rc) {
if (pos < 0) {
wtof("httpsend() pos underflow %d", pos);
break;
}
#if 0
wtof("calling send(%d,%08X,%d,0)",
httpc->socket, &buf[pos], len-pos);
#endif
rc = send(httpc->socket, &buf[pos], len-pos, 0);
#if 0
wtof("send() rc=%d", rc);
#endif
if (rc>0) {
/* update bytes sent count */
httpc->sent += rc;
#if 0
wtof("httpc->sent=%d", httpc->sent);
#endif
}
else {
#if 0
wtof("httpsend() send rc=%d, errno=%d, socket=%d", rc, errno, httpc->socket);
#endif
/* allow for EWOULDBLOCK */
if (errno == EWOULDBLOCK) break;

/* an error occured */
if (httpc->state < CSTATE_DONE) {
/* transtion to done state */
#if 0
wtof("httpsend() changing httpc->state=CSTATE_DONE");
#endif
httpc->state = CSTATE_DONE;
goto quit; /* return with negative rc */
return -1;
}
break;
}
}

rc = pos;
return pos;
}

extern int
httpsend(HTTPC *httpc, const UCHAR *buf, int len)
{
int rc;

if (httpc->chunked) {
/* RFC 7230 chunked transfer encoding */
UCHAR hdr[16];
int hdrlen;

if (len <= 0) return 0;

/* chunk header: hex size + CRLF (convert EBCDIC to ASCII) */
hdrlen = sprintf((char *)hdr, "%x\r\n", len);
http_etoa(hdr, hdrlen);
rc = send_raw(httpc, hdr, hdrlen);
if (rc < 0) return rc;

/* chunk data (already in ASCII from caller) */
rc = send_raw(httpc, buf, len);
if (rc < 0) return rc;

/* chunk trailer: CRLF in ASCII (0x0D 0x0A) */
{
UCHAR crlf[2];
crlf[0] = 0x0D;
crlf[1] = 0x0A;
rc = send_raw(httpc, crlf, 2);
}
if (rc < 0) return rc;

return len;
}

/* non-chunked: send raw */
rc = send_raw(httpc, buf, len);

quit:
#if 0
wtof("httpsend() rc=%d", rc);
#endif
return rc;
}
Loading