Commit e99e8fba authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Always set the reason headerfield when the status field is set, to

keep them in sync.  If you want a custom reason field, set status
first, then reason.

With this in place, HTTP1_Write() doesn't need to worry about them
being OK, and we can polish that code a fair bit.

Turn a couple of boolean arguments into more readable magics.
parent dbd98ce2
......@@ -857,6 +857,8 @@ void HTTP1_Session(struct worker *, struct req *);
int HTTP1_DiscardReqBody(struct req *req);
int HTTP1_CacheReqBody(struct req *req, ssize_t maxsize);
int HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv);
extern const int HTTP1_Req[3];
extern const int HTTP1_Resp[3];
/* cache_http1_deliver.c */
unsigned V1D_FlushReleaseAcct(struct req *req);
......@@ -1030,7 +1032,7 @@ ssize_t HTTP1_Read(struct http_conn *htc, void *d, size_t len);
enum htc_status_e HTTP1_Complete(struct http_conn *htc);
uint16_t HTTP1_DissectRequest(struct req *);
uint16_t HTTP1_DissectResponse(struct http *sp, const struct http_conn *htc);
unsigned HTTP1_Write(const struct worker *w, const struct http *hp, int resp);
unsigned HTTP1_Write(const struct worker *w, const struct http *hp, const int*);
#define HTTPH(a, b, c) extern char b[];
#include "tbl/http_headers.h"
......
......@@ -552,7 +552,9 @@ http_GetStatus(const struct http *hp)
return (hp->status);
}
/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------
* Setting the status will also set the Reason appropriately
*/
void
http_SetStatus(struct http *to, uint16_t status)
......@@ -569,6 +571,7 @@ http_SetStatus(struct http *to, uint16_t status)
assert(status >= 100);
bprintf(buf, "%03d", status);
http_PutField(to, HTTP_HDR_STATUS, buf);
http_SetH(to, HTTP_HDR_REASON, http_Status2Reason(status));
}
/*--------------------------------------------------------------------*/
......
......@@ -322,7 +322,8 @@ V1D_Deliver(struct req *req)
* Send HTTP protocol header, unless interior ESI object
*/
if (!(req->res_mode & RES_ESI_CHILD))
req->resp_hdrbytes += HTTP1_Write(req->wrk, req->resp, 1);
req->resp_hdrbytes +=
HTTP1_Write(req->wrk, req->resp, HTTP1_Resp);
if (req->res_mode & RES_CHUNKED)
WRW_Chunked(req->wrk);
......@@ -429,7 +430,8 @@ V1D_Deliver_Synth(struct req *req)
* Send HTTP protocol header, unless interior ESI object
*/
if (!(req->res_mode & RES_ESI_CHILD))
req->resp_hdrbytes += HTTP1_Write(req->wrk, req->resp, 1);
req->resp_hdrbytes +=
HTTP1_Write(req->wrk, req->resp, HTTP1_Resp);
if (req->res_mode & RES_CHUNKED)
WRW_Chunked(req->wrk);
......
......@@ -327,7 +327,7 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req)
(void)VTCP_blocking(vc->fd); /* XXX: we should timeout instead */
WRW_Reserve(wrk, &vc->fd, bo->vsl, bo->t_prev);
hdrbytes = HTTP1_Write(wrk, hp, 0);
hdrbytes = HTTP1_Write(wrk, hp, HTTP1_Req);
/* Deal with any message-body the request might (still) have */
i = 0;
......
......@@ -49,6 +49,14 @@
#include "vct.h"
const int HTTP1_Req[3] = {
HTTP_HDR_METHOD, HTTP_HDR_URL, HTTP_HDR_PROTO
};
const int HTTP1_Resp[3] = {
HTTP_HDR_PROTO, HTTP_HDR_STATUS, HTTP_HDR_REASON
};
/*--------------------------------------------------------------------*/
void
......@@ -294,55 +302,46 @@ htc_dissect_hdrs(struct http *hp, char *p, const struct http_conn *htc)
*/
static uint16_t
htc_splitline(struct http *hp, const struct http_conn *htc, int req)
htc_splitline(struct http *hp, const struct http_conn *htc, const int *hf)
{
char *p;
int h1, h2, h3;
assert(hf == HTTP1_Req || hf == HTTP1_Resp);
CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
Tcheck(htc->rxbuf);
if (req) {
h1 = HTTP_HDR_METHOD;
h2 = HTTP_HDR_URL;
h3 = HTTP_HDR_PROTO;
} else {
h1 = HTTP_HDR_PROTO;
h2 = HTTP_HDR_STATUS;
h3 = HTTP_HDR_REASON;
}
AZ(hp->hd[h1].b);
AZ(hp->hd[h2].b);
AZ(hp->hd[h3].b);
AZ(hp->hd[hf[0]].b);
AZ(hp->hd[hf[1]].b);
AZ(hp->hd[hf[2]].b);
/* Skip leading LWS */
for (p = htc->rxbuf.b ; vct_islws(*p); p++)
continue;
hp->hd[h1].b = p;
hp->hd[hf[0]].b = p;
/* First field cannot contain SP or CTL */
for (; !vct_issp(*p); p++) {
if (vct_isctl(*p))
return (400);
}
hp->hd[h1].e = p;
assert(Tlen(hp->hd[h1]));
hp->hd[hf[0]].e = p;
assert(Tlen(hp->hd[hf[0]]));
/* Skip SP */
for (; vct_issp(*p); p++) {
if (vct_isctl(*p))
return (400);
}
hp->hd[h2].b = p;
hp->hd[hf[1]].b = p;
/* Second field cannot contain LWS or CTL */
for (; !vct_islws(*p); p++) {
if (vct_isctl(*p))
return (400);
}
hp->hd[h2].e = p;
if (!Tlen(hp->hd[h2]))
hp->hd[hf[1]].e = p;
if (!Tlen(hp->hd[hf[1]]))
return (400);
/* Skip SP */
......@@ -350,23 +349,23 @@ htc_splitline(struct http *hp, const struct http_conn *htc, int req)
if (vct_isctl(*p))
return (400);
}
hp->hd[h3].b = p;
hp->hd[hf[2]].b = p;
/* Third field is optional and cannot contain CTL except TAB */
for (; !vct_iscrlf(p); p++) {
if (vct_isctl(*p) && !vct_issp(*p)) {
hp->hd[h3].b = NULL;
hp->hd[hf[2]].b = NULL;
return (400);
}
}
hp->hd[h3].e = p;
hp->hd[hf[2]].e = p;
/* Skip CRLF */
p += vct_skipcrlf(p);
*hp->hd[h1].e = '\0';
*hp->hd[h2].e = '\0';
*hp->hd[h3].e = '\0';
*hp->hd[hf[0]].e = '\0';
*hp->hd[hf[1]].e = '\0';
*hp->hd[hf[2]].e = '\0';
return (htc_dissect_hdrs(hp, p, htc));
}
......@@ -426,7 +425,7 @@ HTTP1_DissectRequest(struct req *req)
hp = req->http;
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
retval = htc_splitline(hp, htc, 1);
retval = htc_splitline(hp, htc, HTTP1_Req);
if (retval != 0) {
VSLbt(req->vsl, SLT_HttpGarbage, htc->rxbuf);
return (retval);
......@@ -465,7 +464,7 @@ HTTP1_DissectResponse(struct http *hp, const struct http_conn *htc)
CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
if (htc_splitline(hp, htc, 0))
if (htc_splitline(hp, htc, HTTP1_Resp))
retval = 503;
if (retval == 0) {
......@@ -495,6 +494,7 @@ HTTP1_DissectResponse(struct http *hp, const struct http_conn *htc)
assert(retval == 503);
hp->status = retval;
http_SetH(hp, HTTP_HDR_STATUS, "503");
http_SetH(hp, HTTP_HDR_REASON, http_Status2Reason(retval));
}
if (hp->hd[HTTP_HDR_REASON].b == NULL ||
......@@ -507,36 +507,20 @@ HTTP1_DissectResponse(struct http *hp, const struct http_conn *htc)
/*--------------------------------------------------------------------*/
unsigned
HTTP1_Write(const struct worker *w, const struct http *hp, int resp)
HTTP1_Write(const struct worker *w, const struct http *hp, const int *hf)
{
unsigned u, l;
if (resp) {
l = WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], " ");
hp->hd[HTTP_HDR_STATUS].b = WS_Alloc(hp->ws, 4);
AN(hp->hd[HTTP_HDR_STATUS].b);
assert(hf == HTTP1_Req || hf == HTTP1_Resp);
AN(hp->hd[hf[0]].b);
AN(hp->hd[hf[1]].b);
AN(hp->hd[hf[2]].b);
l = WRW_WriteH(w, &hp->hd[hf[0]], " ");
l += WRW_WriteH(w, &hp->hd[hf[1]], " ");
l += WRW_WriteH(w, &hp->hd[hf[2]], "\r\n");
assert(hp->status >= 100 && hp->status <= 999);
sprintf(hp->hd[HTTP_HDR_STATUS].b, "%3d", hp->status);
hp->hd[HTTP_HDR_STATUS].e = hp->hd[HTTP_HDR_STATUS].b + 3;
l += WRW_WriteH(w, &hp->hd[HTTP_HDR_STATUS], " ");
l += WRW_WriteH(w, &hp->hd[HTTP_HDR_REASON], "\r\n");
} else {
AN(hp->hd[HTTP_HDR_URL].b);
l = WRW_WriteH(w, &hp->hd[HTTP_HDR_METHOD], " ");
l += WRW_WriteH(w, &hp->hd[HTTP_HDR_URL], " ");
l += WRW_WriteH(w, &hp->hd[HTTP_HDR_PROTO], "\r\n");
}
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
if (hp->hd[u].b == NULL)
continue;
AN(hp->hd[u].b);
AN(hp->hd[u].e);
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++)
l += WRW_WriteH(w, &hp->hd[u], "\r\n");
}
l += WRW_Write(w, "\r\n", -1);
return (l);
}
......@@ -124,7 +124,7 @@ PipeRequest(struct req *req, struct busyobj *bo)
(void)VTCP_blocking(vc->fd);
WRW_Reserve(wrk, &vc->fd, bo->vsl, req->t_req);
hdrbytes = HTTP1_Write(wrk, bo->bereq, 0);
hdrbytes = HTTP1_Write(wrk, bo->bereq, HTTP1_Req);
if (req->htc->pipeline.b != NULL)
(void)WRW_Write(wrk, req->htc->pipeline.b,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment