Fossil SCM

Build the HTTP reply header in a Blob before sending it on the wire all at once.

drh 2021-12-26 11:41 trunk
Commit 2ac4ab2b2f195f1839c910cf877399839b70202b9620243b08c030107bb941e2
1 file changed +25 -20
+25 -20
--- src/cgi.c
+++ src/cgi.c
@@ -281,10 +281,11 @@
281281
282282
/*
283283
** Do a normal HTTP reply
284284
*/
285285
void cgi_reply(void){
286
+ Blob hdr = BLOB_INITIALIZER;
286287
int total_size;
287288
if( iReplyStatus<=0 ){
288289
iReplyStatus = 200;
289290
zReplyStatus = "OK";
290291
}
@@ -295,39 +296,39 @@
295296
&& fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
296297
){
297298
iReplyStatus = 206;
298299
zReplyStatus = "Partial Content";
299300
}
300
- fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
301
- fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
302
- fprintf(g.httpOut, "Connection: close\r\n");
303
- fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
301
+ blob_appendf(&hdr, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
302
+ blob_appendf(&hdr, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
303
+ blob_appendf(&hdr, "Connection: close\r\n");
304
+ blob_appendf(&hdr, "X-UA-Compatible: IE=edge\r\n");
304305
}else{
305306
assert( rangeEnd==0 );
306
- fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307
+ blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307308
}
308309
if( etag_tag()[0]!=0 ){
309
- fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
310
- fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
310
+ blob_appendf(&hdr, "ETag: %s\r\n", etag_tag());
311
+ blob_appendf(&hdr, "Cache-Control: max-age=%d\r\n", etag_maxage());
311312
if( etag_mtime()>0 ){
312
- fprintf(g.httpOut, "Last-Modified: %s\r\n",
313
+ blob_appendf(&hdr, "Last-Modified: %s\r\n",
313314
cgi_rfc822_datestamp(etag_mtime()));
314315
}
315316
}else if( g.isConst ){
316317
/* isConst means that the reply is guaranteed to be invariant, even
317318
** after configuration changes and/or Fossil binary recompiles. */
318
- fprintf(g.httpOut, "Cache-Control: max-age=315360000, immutable\r\n");
319
+ blob_appendf(&hdr, "Cache-Control: max-age=315360000, immutable\r\n");
319320
}else{
320
- fprintf(g.httpOut, "Cache-control: no-cache\r\n");
321
+ blob_appendf(&hdr, "Cache-control: no-cache\r\n");
321322
}
322323
323324
if( blob_size(&extraHeader)>0 ){
324
- fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
325
+ blob_appendf(&hdr, "%s", blob_buffer(&extraHeader));
325326
}
326327
327328
/* Add headers to turn on useful security options in browsers. */
328
- fprintf(g.httpOut, "X-Frame-Options: SAMEORIGIN\r\n");
329
+ blob_appendf(&hdr, "X-Frame-Options: SAMEORIGIN\r\n");
329330
/* This stops fossil pages appearing in frames or iframes, preventing
330331
** click-jacking attacks on supporting browsers.
331332
**
332333
** Other good headers would be
333334
** Strict-Transport-Security: max-age=62208000
@@ -344,11 +345,11 @@
344345
345346
/* Content intended for logged in users should only be cached in
346347
** the browser, not some shared location.
347348
*/
348349
if( iReplyStatus!=304 ) {
349
- fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
350
+ blob_appendf(&hdr, "Content-Type: %s; charset=utf-8\r\n", zContentType);
350351
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
351352
cgi_combine_header_and_body();
352353
blob_compress(&cgiContent[0], &cgiContent[0]);
353354
}
354355
@@ -359,24 +360,26 @@
359360
int size = blob_size(&cgiContent[i]);
360361
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
361362
blob_reset(&cgiContent[i]);
362363
}
363364
gzip_finish(&cgiContent[0]);
364
- fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
365
- fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
365
+ blob_appendf(&hdr, "Content-Encoding: gzip\r\n");
366
+ blob_appendf(&hdr, "Vary: Accept-Encoding\r\n");
366367
}
367368
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
368369
if( iReplyStatus==206 ){
369
- fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
370
+ blob_appendf(&hdr, "Content-Range: bytes %d-%d/%d\r\n",
370371
rangeStart, rangeEnd-1, total_size);
371372
total_size = rangeEnd - rangeStart;
372373
}
373
- fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
374
+ blob_appendf(&hdr, "Content-Length: %d\r\n", total_size);
374375
}else{
375376
total_size = 0;
376377
}
377
- fprintf(g.httpOut, "\r\n");
378
+ blob_appendf(&hdr, "\r\n");
379
+ fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), g.httpOut);
380
+ blob_reset(&hdr);
378381
if( total_size>0
379382
&& iReplyStatus!=304
380383
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
381384
){
382385
int i, size;
@@ -1742,12 +1745,14 @@
17421745
cgi_trace(zLine);
17431746
zToken = extract_token(zLine, &z);
17441747
if( zToken==0 ){
17451748
malformed_request("malformed HTTP header");
17461749
}
1747
- if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1748
- && fossil_strcmp(zToken,"HEAD")!=0 ){
1750
+ if( fossil_strcmp(zToken,"GET")!=0
1751
+ && fossil_strcmp(zToken,"POST")!=0
1752
+ && fossil_strcmp(zToken,"HEAD")!=0
1753
+ ){
17491754
malformed_request("unsupported HTTP method");
17501755
}
17511756
cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
17521757
cgi_setenv("REQUEST_METHOD",zToken);
17531758
zToken = extract_token(z, &z);
17541759
--- src/cgi.c
+++ src/cgi.c
@@ -281,10 +281,11 @@
281
282 /*
283 ** Do a normal HTTP reply
284 */
285 void cgi_reply(void){
 
286 int total_size;
287 if( iReplyStatus<=0 ){
288 iReplyStatus = 200;
289 zReplyStatus = "OK";
290 }
@@ -295,39 +296,39 @@
295 && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
296 ){
297 iReplyStatus = 206;
298 zReplyStatus = "Partial Content";
299 }
300 fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
301 fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
302 fprintf(g.httpOut, "Connection: close\r\n");
303 fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
304 }else{
305 assert( rangeEnd==0 );
306 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
307 }
308 if( etag_tag()[0]!=0 ){
309 fprintf(g.httpOut, "ETag: %s\r\n", etag_tag());
310 fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
311 if( etag_mtime()>0 ){
312 fprintf(g.httpOut, "Last-Modified: %s\r\n",
313 cgi_rfc822_datestamp(etag_mtime()));
314 }
315 }else if( g.isConst ){
316 /* isConst means that the reply is guaranteed to be invariant, even
317 ** after configuration changes and/or Fossil binary recompiles. */
318 fprintf(g.httpOut, "Cache-Control: max-age=315360000, immutable\r\n");
319 }else{
320 fprintf(g.httpOut, "Cache-control: no-cache\r\n");
321 }
322
323 if( blob_size(&extraHeader)>0 ){
324 fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
325 }
326
327 /* Add headers to turn on useful security options in browsers. */
328 fprintf(g.httpOut, "X-Frame-Options: SAMEORIGIN\r\n");
329 /* This stops fossil pages appearing in frames or iframes, preventing
330 ** click-jacking attacks on supporting browsers.
331 **
332 ** Other good headers would be
333 ** Strict-Transport-Security: max-age=62208000
@@ -344,11 +345,11 @@
344
345 /* Content intended for logged in users should only be cached in
346 ** the browser, not some shared location.
347 */
348 if( iReplyStatus!=304 ) {
349 fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
350 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
351 cgi_combine_header_and_body();
352 blob_compress(&cgiContent[0], &cgiContent[0]);
353 }
354
@@ -359,24 +360,26 @@
359 int size = blob_size(&cgiContent[i]);
360 if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
361 blob_reset(&cgiContent[i]);
362 }
363 gzip_finish(&cgiContent[0]);
364 fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
365 fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
366 }
367 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
368 if( iReplyStatus==206 ){
369 fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
370 rangeStart, rangeEnd-1, total_size);
371 total_size = rangeEnd - rangeStart;
372 }
373 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
374 }else{
375 total_size = 0;
376 }
377 fprintf(g.httpOut, "\r\n");
 
 
378 if( total_size>0
379 && iReplyStatus!=304
380 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
381 ){
382 int i, size;
@@ -1742,12 +1745,14 @@
1742 cgi_trace(zLine);
1743 zToken = extract_token(zLine, &z);
1744 if( zToken==0 ){
1745 malformed_request("malformed HTTP header");
1746 }
1747 if( fossil_strcmp(zToken,"GET")!=0 && fossil_strcmp(zToken,"POST")!=0
1748 && fossil_strcmp(zToken,"HEAD")!=0 ){
 
 
1749 malformed_request("unsupported HTTP method");
1750 }
1751 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1752 cgi_setenv("REQUEST_METHOD",zToken);
1753 zToken = extract_token(z, &z);
1754
--- src/cgi.c
+++ src/cgi.c
@@ -281,10 +281,11 @@
281
282 /*
283 ** Do a normal HTTP reply
284 */
285 void cgi_reply(void){
286 Blob hdr = BLOB_INITIALIZER;
287 int total_size;
288 if( iReplyStatus<=0 ){
289 iReplyStatus = 200;
290 zReplyStatus = "OK";
291 }
@@ -295,39 +296,39 @@
296 && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
297 ){
298 iReplyStatus = 206;
299 zReplyStatus = "Partial Content";
300 }
301 blob_appendf(&hdr, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
302 blob_appendf(&hdr, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
303 blob_appendf(&hdr, "Connection: close\r\n");
304 blob_appendf(&hdr, "X-UA-Compatible: IE=edge\r\n");
305 }else{
306 assert( rangeEnd==0 );
307 blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
308 }
309 if( etag_tag()[0]!=0 ){
310 blob_appendf(&hdr, "ETag: %s\r\n", etag_tag());
311 blob_appendf(&hdr, "Cache-Control: max-age=%d\r\n", etag_maxage());
312 if( etag_mtime()>0 ){
313 blob_appendf(&hdr, "Last-Modified: %s\r\n",
314 cgi_rfc822_datestamp(etag_mtime()));
315 }
316 }else if( g.isConst ){
317 /* isConst means that the reply is guaranteed to be invariant, even
318 ** after configuration changes and/or Fossil binary recompiles. */
319 blob_appendf(&hdr, "Cache-Control: max-age=315360000, immutable\r\n");
320 }else{
321 blob_appendf(&hdr, "Cache-control: no-cache\r\n");
322 }
323
324 if( blob_size(&extraHeader)>0 ){
325 blob_appendf(&hdr, "%s", blob_buffer(&extraHeader));
326 }
327
328 /* Add headers to turn on useful security options in browsers. */
329 blob_appendf(&hdr, "X-Frame-Options: SAMEORIGIN\r\n");
330 /* This stops fossil pages appearing in frames or iframes, preventing
331 ** click-jacking attacks on supporting browsers.
332 **
333 ** Other good headers would be
334 ** Strict-Transport-Security: max-age=62208000
@@ -344,11 +345,11 @@
345
346 /* Content intended for logged in users should only be cached in
347 ** the browser, not some shared location.
348 */
349 if( iReplyStatus!=304 ) {
350 blob_appendf(&hdr, "Content-Type: %s; charset=utf-8\r\n", zContentType);
351 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
352 cgi_combine_header_and_body();
353 blob_compress(&cgiContent[0], &cgiContent[0]);
354 }
355
@@ -359,24 +360,26 @@
360 int size = blob_size(&cgiContent[i]);
361 if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
362 blob_reset(&cgiContent[i]);
363 }
364 gzip_finish(&cgiContent[0]);
365 blob_appendf(&hdr, "Content-Encoding: gzip\r\n");
366 blob_appendf(&hdr, "Vary: Accept-Encoding\r\n");
367 }
368 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
369 if( iReplyStatus==206 ){
370 blob_appendf(&hdr, "Content-Range: bytes %d-%d/%d\r\n",
371 rangeStart, rangeEnd-1, total_size);
372 total_size = rangeEnd - rangeStart;
373 }
374 blob_appendf(&hdr, "Content-Length: %d\r\n", total_size);
375 }else{
376 total_size = 0;
377 }
378 blob_appendf(&hdr, "\r\n");
379 fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), g.httpOut);
380 blob_reset(&hdr);
381 if( total_size>0
382 && iReplyStatus!=304
383 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
384 ){
385 int i, size;
@@ -1742,12 +1745,14 @@
1745 cgi_trace(zLine);
1746 zToken = extract_token(zLine, &z);
1747 if( zToken==0 ){
1748 malformed_request("malformed HTTP header");
1749 }
1750 if( fossil_strcmp(zToken,"GET")!=0
1751 && fossil_strcmp(zToken,"POST")!=0
1752 && fossil_strcmp(zToken,"HEAD")!=0
1753 ){
1754 malformed_request("unsupported HTTP method");
1755 }
1756 cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
1757 cgi_setenv("REQUEST_METHOD",zToken);
1758 zToken = extract_token(z, &z);
1759

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button