Fossil

Check-in [02740c2c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Further changes trying to get ETags to work well. But as I type this, I feel like this design is not working out well and I am about ready to start over from scratch. This check-in is just to preserve work in case I want to come back to it later.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | etags
Files: files | file ages | folders
SHA3-256:02740c2c47ae7c35922e3333c4f63863835f28f06fde01664bfa7ced3da9138a
User & Date: drh 2018-02-24 18:39:18
Context
2018-02-24
18:39
Further changes trying to get ETags to work well. But as I type this, I feel like this design is not working out well and I am about ready to start over from scratch. This check-in is just to preserve work in case I want to come back to it later. Closed-Leaf check-in: 02740c2c user: drh tags: etags
17:08
Fix ETags support for when compiling with FOSSIL_ENABLE_TH1_HOOKS. check-in: 43a66b58 user: drh tags: etags
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/cgi.c.

256
257
258
259
260
261
262





263
264
265
266
267
268
269
270
271
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
    fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
    fprintf(g.httpOut, "Connection: close\r\n");
    fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
  }else{
    fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
  }





  zETag = etag_generate(-1);
  if( zETag ){
    fprintf(g.httpOut, "ETag: %s\r\n", zETag);
    fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
  }

  if( blob_size(&extraHeader)>0 ){
    fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
  }
................................................................................
  ** deliberate inclusion of external resources, such as JavaScript syntax
  ** highlighter scripts.
  **
  ** These headers are probably best added by the web server hosting fossil as
  ** a CGI script.
  */

  if( g.isConst ){
    /* constant means that the input URL will _never_ generate anything
    ** else. In the case of attachments, the contents won't change because
    ** an attempt to change them generates a new attachment number. In the
    ** case of most /getfile calls for specific versions, the only way the
    ** content changes is if someone breaks the SCM. And if that happens, a
    ** stale cache is the least of the problem. So we provide an Expires
    ** header set to a reasonable period (default: one week).
    */
    fprintf(g.httpOut, "Cache-control: max-age=28800\r\n");
  }else{
    fprintf(g.httpOut, "Cache-control: no-cache\r\n");
  }

  /* Content intended for logged in users should only be cached in
  ** the browser, not some shared location.
  */
  fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
  if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
    cgi_combine_header_and_body();
    blob_compress(&cgiContent[0], &cgiContent[0]);







>
>
>
>
>
|
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<







256
257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
...
288
289
290
291
292
293
294














295
296
297
298
299
300
301
    fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
    fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
    fprintf(g.httpOut, "Connection: close\r\n");
    fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
  }else{
    fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
  }
  if( g.isConst ){
    /* The g.isConst flag means that the result is immutable, even for
    ** after configuration changes and/or rebuilds of the Fossil binary.
    */
    fprintf(g.httpOut, "Cache-Control: max-age=31536000\r\n");
  }else if( (zETag = etag_generate(-1))!=0 ){

    fprintf(g.httpOut, "ETag: %s\r\n", zETag);
    fprintf(g.httpOut, "Cache-Control: max-age=%d\r\n", etag_maxage());
  }

  if( blob_size(&extraHeader)>0 ){
    fprintf(g.httpOut, "%s", blob_buffer(&extraHeader));
  }
................................................................................
  ** deliberate inclusion of external resources, such as JavaScript syntax
  ** highlighter scripts.
  **
  ** These headers are probably best added by the web server hosting fossil as
  ** a CGI script.
  */















  /* Content intended for logged in users should only be cached in
  ** the browser, not some shared location.
  */
  fprintf(g.httpOut, "Content-Type: %s; charset=utf-8\r\n", zContentType);
  if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
    cgi_combine_header_and_body();
    blob_compress(&cgiContent[0], &cgiContent[0]);

Changes to src/doc.c.

830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
...
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
...
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
   138, 163,  69,  96, 115,   0, 147,  72,  72,  84,  28,  14,  79,  86,
   233, 230,  23, 113,  26, 160, 128,   3,  10,  58, 129, 103,  14, 159,
   214, 163, 146, 117, 238, 213, 154, 128, 151, 109,  84,  64, 217,  13,
    27,  10, 228,  39,   2, 235, 164, 168,  74,   8,   0,  59,
};

/*
** WEBPAGE: logo
**
** Return the logo image.  This image is available to anybody who can see
** the login page.  It is designed for use in the upper left-hand corner
** of the header.
*/
void logo_page(void){
  Blob logo;
................................................................................
  blob_zero(&logo);
  db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
  if( blob_size(&logo)==0 ){
    blob_init(&logo, (char*)aLogo, sizeof(aLogo));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&logo);
  g.isConst = 1;
}

/*
** The default background image:  a 16x16 white GIF
*/
static const unsigned char aBackground[] = {
    71,  73,  70,  56,  57,  97,  16,   0,  16,   0,
................................................................................
     0,   0,  16,   0,  16,   0,   0,   2,  14, 132,
   143, 169, 203, 237,  15, 163, 156, 180, 218, 139,
   179,  62,   5,   0,  59,
};


/*
** WEBPAGE: background
**
** Return the background image.  If no background image is defined, a
** built-in 16x16 pixel white GIF is returned.
*/
void background_page(void){
  Blob bgimg;
  char *zMime;
................................................................................
  blob_zero(&bgimg);
  db_blob(&bgimg, "SELECT value FROM config WHERE name='background-image'");
  if( blob_size(&bgimg)==0 ){
    blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&bgimg);
  g.isConst = 1;
}


/*
** WEBPAGE: docsrch
**
** Search for documents that match a user-supplied full-text search pattern.







|







 







<







 







|







 







<







830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
...
848
849
850
851
852
853
854

855
856
857
858
859
860
861
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
...
881
882
883
884
885
886
887

888
889
890
891
892
893
894
   138, 163,  69,  96, 115,   0, 147,  72,  72,  84,  28,  14,  79,  86,
   233, 230,  23, 113,  26, 160, 128,   3,  10,  58, 129, 103,  14, 159,
   214, 163, 146, 117, 238, 213, 154, 128, 151, 109,  84,  64, 217,  13,
    27,  10, 228,  39,   2, 235, 164, 168,  74,   8,   0,  59,
};

/*
** WEBPAGE: logo           config
**
** Return the logo image.  This image is available to anybody who can see
** the login page.  It is designed for use in the upper left-hand corner
** of the header.
*/
void logo_page(void){
  Blob logo;
................................................................................
  blob_zero(&logo);
  db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'");
  if( blob_size(&logo)==0 ){
    blob_init(&logo, (char*)aLogo, sizeof(aLogo));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&logo);

}

/*
** The default background image:  a 16x16 white GIF
*/
static const unsigned char aBackground[] = {
    71,  73,  70,  56,  57,  97,  16,   0,  16,   0,
................................................................................
     0,   0,  16,   0,  16,   0,   0,   2,  14, 132,
   143, 169, 203, 237,  15, 163, 156, 180, 218, 139,
   179,  62,   5,   0,  59,
};


/*
** WEBPAGE: background     const
**
** Return the background image.  If no background image is defined, a
** built-in 16x16 pixel white GIF is returned.
*/
void background_page(void){
  Blob bgimg;
  char *zMime;
................................................................................
  blob_zero(&bgimg);
  db_blob(&bgimg, "SELECT value FROM config WHERE name='background-image'");
  if( blob_size(&bgimg)==0 ){
    blob_init(&bgimg, (char*)aBackground, sizeof(aBackground));
  }
  cgi_set_content_type(zMime);
  cgi_set_content(&bgimg);

}


/*
** WEBPAGE: docsrch
**
** Search for documents that match a user-supplied full-text search pattern.

Changes to src/etag.c.

127
128
129
130
131
132
133
134


135

136
137
138
139
140
141
142
143
144
145
146
147
148
149


150
151
152
153
154
155
156
**
** After each call to these routines, the HTTP_IF_NONE_MATCH cookie
** is checked, and if it contains a compatible ETag, then a
** 304 Not Modified return is generated and execution aborts.  This
** routine does not return if the 304 is generated.
*/
void etag_require(int code){
  if( (mEtag & code)==code ) return;


  mEtag |= code;

  etag_check();
}
void etag_require_hash(const char *zHash){
  if( zHash ){
    zEHash = zHash;
    mEtag = ETAG_HASH;
    etag_check();
  }
}

/* Return an appropriate max-age.
*/
int etag_maxage(void){
  if( mEtag ) return 1;


  return 3600*24;
}

/* Generate an appropriate ETags value that captures all requirements.
** Space is obtained from fossil_malloc().
**
** The argument is the mask of attributes to include in the ETag.







|
>
>
|
>













|
>
>







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
**
** After each call to these routines, the HTTP_IF_NONE_MATCH cookie
** is checked, and if it contains a compatible ETag, then a
** 304 Not Modified return is generated and execution aborts.  This
** routine does not return if the 304 is generated.
*/
void etag_require(int code){
  if( code==ETAG_CONST ){
    mEtag = code;
  }else{
    mEtag |= code;
  }
  etag_check();
}
void etag_require_hash(const char *zHash){
  if( zHash ){
    zEHash = zHash;
    mEtag = ETAG_HASH;
    etag_check();
  }
}

/* Return an appropriate max-age.
*/
int etag_maxage(void){
  if( mEtag & (ETAG_DYNAMIC|ETAG_COOKIE) ) return 0;
  if( mEtag & (ETAG_DATA|ETAG_HASH) ) return 60;
  if( mEtag & (ETAG_CONFIG) ) return 300;
  return 3600*24;
}

/* Generate an appropriate ETags value that captures all requirements.
** Space is obtained from fossil_malloc().
**
** The argument is the mask of attributes to include in the ETag.

Changes to src/info.c.

1686
1687
1688
1689
1690
1691
1692

1693
1694
1695

1696
1697
1698
1699
1700
1701
1702
  if( rid==0 ){
    rid = name_to_rid_www("name");
  }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  if( rid==0 ) fossil_redirect_home();
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);

  if( fossil_strcmp(P("name"), zUuid)==0 && login_is_nobody() ){
    g.isConst = 1;
  }

  free(zUuid);
  zMime = P("m");
  if( zMime==0 ){
    char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
                              " WHERE mlink.fid=%d"
                              "   AND filename.fnid=mlink.fnid", rid);
    if( !zFName ){







>



>







1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
  if( rid==0 ){
    rid = name_to_rid_www("name");
  }
  login_check_credentials();
  if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
  if( rid==0 ) fossil_redirect_home();
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
#if 0
  if( fossil_strcmp(P("name"), zUuid)==0 && login_is_nobody() ){
    g.isConst = 1;
  }
#endif
  free(zUuid);
  zMime = P("m");
  if( zMime==0 ){
    char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
                              " WHERE mlink.fid=%d"
                              "   AND filename.fnid=mlink.fnid", rid);
    if( !zFName ){

Changes to src/style.c.

778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
...
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837



838
839
840
841
842


843
844
845
846
847
848
849
850
851
852
853





854
855
856
857
858
859
860
861
862
863
  found = containsSelector(blob_str(&css), zSelector);
  fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
  blob_reset(&css);
}


/*
** WEBPAGE: style.css
**
** Return the style sheet.
*/
void page_style_css(void){
  Blob css;
  int i;
  int isInit = 0;
................................................................................
  */
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
  Th_Store("home", g.zTop);
  image_url_var("logo");
  image_url_var("background");
  Th_Render(blob_str(&css));

  /* Tell CGI that the content returned by this page is considered cacheable */
  g.isConst = 1;
}

/*
** WEBPAGE: builtin
** URL:  builtin/FILENAME
**
** Return the built-in text given by FILENAME.  This is used internally 
** by many Fossil web pages to load built-in javascript files.



*/
void page_builtin_text(void){
  Blob out;
  const char *zName = P("name");
  const char *zTxt = 0;


  if( zName ) zTxt = builtin_text(zName);
  if( zTxt==0 ){
    cgi_set_status(404, "Not Found");
    @ File "%h(zName)" not found
    return;
  }
  if( sqlite3_strglob("*.js", zName)==0 ){
    cgi_set_content_type("application/javascript");
  }else{
    cgi_set_content_type("text/plain");
  }





  blob_init(&out, zTxt, -1);
  cgi_set_content(&out);
  g.isConst = 1;
}


/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time







|







 







<
<
<








>
>
>





>
>











>
>
>
>
>


<







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
...
820
821
822
823
824
825
826



827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862

863
864
865
866
867
868
869
  found = containsSelector(blob_str(&css), zSelector);
  fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
  blob_reset(&css);
}


/*
** WEBPAGE: style.css      config
**
** Return the style sheet.
*/
void page_style_css(void){
  Blob css;
  int i;
  int isInit = 0;
................................................................................
  */
  Th_Store("baseurl", g.zBaseURL);
  Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
  Th_Store("home", g.zTop);
  image_url_var("logo");
  image_url_var("background");
  Th_Render(blob_str(&css));



}

/*
** WEBPAGE: builtin
** URL:  builtin/FILENAME
**
** Return the built-in text given by FILENAME.  This is used internally 
** by many Fossil web pages to load built-in javascript files.
**
** If the id= query parameter is present, then Fossil assumes that the
** result is immutable and sets a very large cache retention time (1 year).
*/
void page_builtin_text(void){
  Blob out;
  const char *zName = P("name");
  const char *zTxt = 0;
  const char *zId = P("id");
  int nId;
  if( zName ) zTxt = builtin_text(zName);
  if( zTxt==0 ){
    cgi_set_status(404, "Not Found");
    @ File "%h(zName)" not found
    return;
  }
  if( sqlite3_strglob("*.js", zName)==0 ){
    cgi_set_content_type("application/javascript");
  }else{
    cgi_set_content_type("text/plain");
  }
  if( zId && (nId = (int)strlen(zId))>=8 && strncmp(zId,MANIFEST_UUID,nId)==0 ){
    g.isConst = 1;
  }else{
    etag_require(ETAG_CONST);
  }
  blob_init(&out, zTxt, -1);
  cgi_set_content(&out);

}


/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time