Diff
Not logged in

Differences From Artifact [023e3fcb4d]:

To Artifact [8fbaa71bf0]:


239
240
241
242
243
244
245
246

247
248
249
250
251
252
253
254
255
256
257
258
259
260


261

262
263
264
265
266
267
268
239
240
241
242
243
244
245

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270







-
+














+
+
-
+







  cgi_combine_header_and_body();
  return blob_buffer(&cgiContent[0]);
}

/*
** Additional information used to form the HTTP reply
*/
static const char *zContentType = "text/html";   /* Content type of the reply */
static const char *zReplyMimeType = "text/html"; /* Content type of the reply */
static const char *zReplyStatus = "OK";          /* Reply status description */
static int iReplyStatus = 200;               /* Reply status code */
static Blob extraHeader = BLOB_INITIALIZER;  /* Extra header text */
static int rangeStart = 0;                   /* Start of Range: */
static int rangeEnd = 0;                     /* End of Range: plus 1 */

/*
** Set the reply content type.
**
** The reply content type defaults to "text/html".  It only needs to be
** changed (by calling this routine) in the exceptional case where some
** other content type is being returned.
*/
void cgi_set_content_type(const char *zType){
  int i;
  for(i=0; zType[i]>='-' && zType[i]<='z'; i++){}
  zContentType = fossil_strdup(zType);
  zReplyMimeType = fossil_strndup(zType, i);
}

/*
** Erase any existing reply content.  Replace is with a pNewContent.
**
** This routine erases pNewContent.  In other words, it move pNewContent
** into the content buffer.
334
335
336
337
338
339
340
341

342
343
344


345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360


361
362

363
364
365
366
367
368
369
336
337
338
339
340
341
342

343
344


345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360


361
362
363

364
365
366
367
368
369
370
371







-
+

-
-
+
+














-
-
+
+

-
+







*/
static int is_gzippable(void){
  if( g.fNoHttpCompress ) return 0;
  if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0;
  /* Maintenance note: this oddball structure is intended to make
  ** adding new mimetypes to this list less of a performance hit than
  ** doing a strcmp/glob over a growing set of compressible types. */
  switch(zContentType ? *zContentType : 0){
  switch(zReplyMimeType ? *zReplyMimeType : 0){
    case (int)'a':
      if(0==fossil_strncmp("application/",zContentType,12)){
        const char * z = &zContentType[12];
      if(0==fossil_strncmp("application/",zReplyMimeType,12)){
        const char * z = &zReplyMimeType[12];
        switch(*z){
          case (int)'j':
            return fossil_strcmp("javascript", z)==0
                || fossil_strcmp("json", z)==0;
          case (int)'w': return fossil_strcmp("wasm", z)==0;
          case (int)'x':
            return fossil_strcmp("x-tcl", z)==0
                || fossil_strcmp("x-tar", z)==0;
          default:
            return sqlite3_strglob("*xml", z)==0;
        }
      }
      break;
    case (int)'i':
      return fossil_strcmp(zContentType, "image/svg+xml")==0
        || fossil_strcmp(zContentType, "image/vnd.microsoft.icon")==0;
      return fossil_strcmp(zReplyMimeType, "image/svg+xml")==0
        || fossil_strcmp(zReplyMimeType, "image/vnd.microsoft.icon")==0;
    case (int)'t':
      return fossil_strncmp(zContentType, "text/", 5)==0;
      return fossil_strncmp(zReplyMimeType, "text/", 5)==0;
  }
  return 0;
}


/*
** The following routines read or write content from/to the wire for
447
448
449
450
451
452
453
454

455
456
457
458
459
460
461
462
463
464
465


466
467
468
469
470
471
472
449
450
451
452
453
454
455

456
457
458
459
460
461
462
463
464
465


466
467
468
469
470
471
472
473
474







-
+









-
-
+
+







    fflush(g.httpOut);
  }
}

/*
** Given a Content-Type value, returns a string suitable for appending
** to the Content-Type header for adding (or not) the "; charset=..."
** part. It returns an empty string for most types or if zContentType
** part. It returns an empty string for most types or if zReplyMimeType
** is NULL.
**
** See forum post f60dece061c364d1 for the discussions which lead to
** this. Previously we always appended the charset, but WASM loaders
** are pedantic and refuse to load any responses which have a
** charset. Also, adding a charset is not strictly appropriate for
** most types (and not required for many others which may ostensibly
** benefit from one, as detailed in that forum post).
*/
static const char * content_type_charset(const char *zContentType){
  if(0==fossil_strncmp(zContentType,"text/",5)){
static const char * content_type_charset(const char *zReplyMimeType){
  if(0==fossil_strncmp(zReplyMimeType,"text/",5)){
    return "; charset=utf-8";
  }
  return "";
}

/*
** Generate the reply to a web request.  The output might be an
498
499
500
501
502
503
504
505

506
507
508
509
510
511
512
500
501
502
503
504
505
506

507
508
509
510
511
512
513
514







-
+







    blob_appendf(&hdr, "X-UA-Compatible: IE=edge\r\n");
  }else{
    assert( rangeEnd==0 );
    blob_appendf(&hdr, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
  }
  if( etag_tag()[0]!=0
   && iReplyStatus==200
   && strcmp(zContentType,"text/html")!=0
   && strcmp(zReplyMimeType,"text/html")!=0
  ){
    /* Do not cache HTML replies as those will have been generated and
    ** will likely, therefore, contains a nonce and we want that nonce to
    ** be different every time. */
    blob_appendf(&hdr, "ETag: \"%s\"\r\n", etag_tag());
    blob_appendf(&hdr, "Cache-Control: max-age=%d\r\n", etag_maxage());
    if( etag_mtime()>0 ){
540
541
542
543
544
545
546
547
548
549



550
551
552
553
554
555
556
542
543
544
545
546
547
548



549
550
551
552
553
554
555
556
557
558







-
-
-
+
+
+







  ** highlighter scripts.
  **
  ** These headers are probably best added by the web server hosting fossil as
  ** a CGI script.
  */

  if( iReplyStatus!=304 ) {
    blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType,
                 content_type_charset(zContentType));
    if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
    blob_appendf(&hdr, "Content-Type: %s%s\r\n", zReplyMimeType,
                 content_type_charset(zReplyMimeType));
    if( fossil_strcmp(zReplyMimeType,"application/x-fossil")==0 ){
      cgi_combine_header_and_body();
      blob_compress(&cgiContent[0], &cgiContent[0]);
    }

    if( is_gzippable() && iReplyStatus!=206 ){
      int i;
      gzip_begin(0);
2019
2020
2021
2022
2023
2024
2025
2026

2027
2028
2029
2030
2031
2032
2033
2021
2022
2023
2024
2025
2026
2027

2028
2029
2030
2031
2032
2033
2034
2035







-
+







static NORETURN void malformed_request(const char *zMsg, ...){
  va_list ap;
  char *z;
  va_start(ap, zMsg);
  z = vmprintf(zMsg, ap);
  va_end(ap);
  cgi_set_status(400, "Bad Request");
  zContentType = "text/plain";
  zReplyMimeType = "text/plain";
  if( g.zReqType==0 ) g.zReqType = "WWW";
  if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){
    const char *zServer = PD("SERVER_SOFTWARE","");
    cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z);
  }else{
    cgi_printf("Bad %s Request: %s\n", g.zReqType, z);
  }