Fossil SCM
Some of the comments in cgi.c had become stale after years of evolution. Try to bring them up-to-date.
Commit
37ccaafddb2bd4e95f288d62a0e0e1e32be756fee7bb0902c389888d29286925
Parent
f9c2d23f297f23c…
1 file changed
+88
-25
+88
-25
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -13,16 +13,53 @@ | ||
| 13 | 13 | ** [email protected] |
| 14 | 14 | ** http://www.hwaci.com/drh/ |
| 15 | 15 | ** |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 18 | -** This file contains C functions and procedures used by CGI programs | |
| 19 | -** (Fossil launched as CGI) to interpret CGI environment variables, | |
| 20 | -** gather the results, and send they reply back to the CGI server. | |
| 21 | -** This file also contains routines for running a simple web-server | |
| 22 | -** (the "fossil ui" or "fossil server" command) and launching subprocesses | |
| 23 | -** to handle each inbound HTTP request using CGI. | |
| 18 | +** This file began as a set of C functions and procedures used intepret | |
| 19 | +** CGI environment variables for Fossil web pages that were invoked by | |
| 20 | +** CGI. That's where the file name comes from. But over the years it | |
| 21 | +** has grown to incorporate lots of related functionality, including: | |
| 22 | +** | |
| 23 | +** * Interpreting CGI environment variables when Fossil is run as | |
| 24 | +** CGI (the original purpose). | |
| 25 | +** | |
| 26 | +** * Interpreting HTTP requests received directly or via an SSH tunnel. | |
| 27 | +** | |
| 28 | +** * Interpreting SCGI requests | |
| 29 | +** | |
| 30 | +** * Generating appropriate replies to CGI, SCGI, and HTTP requests. | |
| 31 | +** | |
| 32 | +** * Listening for incoming HTTP requests and dispatching them. | |
| 33 | +** (Used by "fossil ui" and "fossil server", for example). | |
| 34 | +** | |
| 35 | +** So, even though the name of this file implies that it only deals with | |
| 36 | +** CGI, in fact, the code in this file is used to interpret webpage requests | |
| 37 | +** received by a variety of means, and to generate well-formatted replies | |
| 38 | +** to those requests. | |
| 39 | +** | |
| 40 | +** The code in this file abstracts the web-request so that downstream | |
| 41 | +** modules that generate the body of the reply (based on the requested page) | |
| 42 | +** do not need to know if the request is coming from CGI, direct HTTP, | |
| 43 | +** SCGI, or some other means. | |
| 44 | +** | |
| 45 | +** This module gathers information about web page request into a key/value | |
| 46 | +** store. Keys and values come from: | |
| 47 | +** | |
| 48 | +** * Query parameters | |
| 49 | +** * POST parameter | |
| 50 | +** * Cookies | |
| 51 | +** * Environment variables | |
| 52 | +** | |
| 53 | +** The parameters are accessed using cgi_parameter() and similar functions | |
| 54 | +** or their convenience macros P() and similar. | |
| 55 | +** | |
| 56 | +** Environment variable parameters are set as if the request were coming | |
| 57 | +** in over CGI even if the request arrived via SCGI or direct HTTP. Thus | |
| 58 | +** the downstream modules that are trying to interpret the request do not | |
| 59 | +** need to know the request protocol - they can just request the values | |
| 60 | +** of environment variables and everything will always work. | |
| 24 | 61 | ** |
| 25 | 62 | ** This file contains routines used by Fossil when it is acting as a |
| 26 | 63 | ** CGI client. For the code used by Fossil when it is acting as a |
| 27 | 64 | ** CGI server (for the /ext webpage) see the "extcgi.c" source file. |
| 28 | 65 | */ |
| @@ -92,16 +129,27 @@ | ||
| 92 | 129 | #define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */ |
| 93 | 130 | |
| 94 | 131 | #endif /* INTERFACE */ |
| 95 | 132 | |
| 96 | 133 | /* |
| 97 | -** The HTTP reply is generated in two pieces: the header and the body. | |
| 134 | +** The reply content is generated in two pieces: the header and the body. | |
| 98 | 135 | ** These pieces are generated separately because they are not necessarily |
| 99 | 136 | ** produced in order. Parts of the header might be built after all or |
| 100 | 137 | ** part of the body. The header and body are accumulated in separate |
| 101 | 138 | ** Blob structures then output sequentially once everything has been |
| 102 | 139 | ** built. |
| 140 | +** | |
| 141 | +** Do not confuse the content header with the HTTP header. The content header | |
| 142 | +** is generated by downstream code. The HTTP header is generated by the | |
| 143 | +** cgi_reply() routine below. | |
| 144 | +** | |
| 145 | +** The content header and contenty body are *approximately* the <head> | |
| 146 | +** element and the <body> elements for HTML replies. However this is only | |
| 147 | +** approximate. The content header also includes parts of <body> that | |
| 148 | +** show the banner and menu bar at the top of each page. Also note that | |
| 149 | +** not all replies are HTML, but there can still be separate header and | |
| 150 | +** body sections of the content. | |
| 103 | 151 | ** |
| 104 | 152 | ** The cgi_destination() interface switches between the buffers. |
| 105 | 153 | */ |
| 106 | 154 | static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER }; |
| 107 | 155 | static Blob *pContent = &cgiContent[0]; |
| @@ -124,51 +172,53 @@ | ||
| 124 | 172 | } |
| 125 | 173 | } |
| 126 | 174 | } |
| 127 | 175 | |
| 128 | 176 | /* |
| 129 | -** Check to see if the header contains the zNeedle string. Return true | |
| 130 | -** if it does and false if it does not. | |
| 177 | +** Check to see if the content header or body contains the zNeedle string. | |
| 178 | +** Return true if it does and false if it does not. | |
| 131 | 179 | */ |
| 132 | 180 | int cgi_header_contains(const char *zNeedle){ |
| 133 | 181 | return strstr(blob_str(&cgiContent[0]), zNeedle)!=0; |
| 134 | 182 | } |
| 135 | 183 | int cgi_body_contains(const char *zNeedle){ |
| 136 | 184 | return strstr(blob_str(&cgiContent[1]), zNeedle)!=0; |
| 137 | 185 | } |
| 138 | 186 | |
| 139 | 187 | /* |
| 140 | -** Append reply content to what already exists. | |
| 188 | +** Append new reply content to what already exists. | |
| 141 | 189 | */ |
| 142 | 190 | void cgi_append_content(const char *zData, int nAmt){ |
| 143 | 191 | blob_append(pContent, zData, nAmt); |
| 144 | 192 | } |
| 145 | 193 | |
| 146 | 194 | /* |
| 147 | -** Reset the HTTP reply text to be an empty string. | |
| 195 | +** Reset both reply content buffers to be empty. | |
| 148 | 196 | */ |
| 149 | 197 | void cgi_reset_content(void){ |
| 150 | 198 | blob_reset(&cgiContent[0]); |
| 151 | 199 | blob_reset(&cgiContent[1]); |
| 152 | 200 | } |
| 153 | 201 | |
| 154 | 202 | /* |
| 155 | -** Return a pointer to the CGI output blob. | |
| 203 | +** Return a pointer to Blob that is currently accumulating reply content. | |
| 156 | 204 | */ |
| 157 | 205 | Blob *cgi_output_blob(void){ |
| 158 | 206 | return pContent; |
| 159 | 207 | } |
| 160 | 208 | |
| 161 | 209 | /* |
| 162 | -** Return complete text of the output header | |
| 210 | +** Return the content header as a text string | |
| 163 | 211 | */ |
| 164 | 212 | const char *cgi_header(void){ |
| 165 | 213 | return blob_str(&cgiContent[0]); |
| 166 | 214 | } |
| 167 | 215 | |
| 168 | 216 | /* |
| 169 | -** Combine the header and body of the CGI into a single string. | |
| 217 | +** Combine the header and body content all into the header buffer. | |
| 218 | +** In other words, append the body content to the end of the header | |
| 219 | +** content. | |
| 170 | 220 | */ |
| 171 | 221 | static void cgi_combine_header_and_body(void){ |
| 172 | 222 | int size = blob_size(&cgiContent[1]); |
| 173 | 223 | if( size>0 ){ |
| 174 | 224 | blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size); |
| @@ -175,11 +225,11 @@ | ||
| 175 | 225 | blob_reset(&cgiContent[1]); |
| 176 | 226 | } |
| 177 | 227 | } |
| 178 | 228 | |
| 179 | 229 | /* |
| 180 | -** Return a pointer to the HTTP reply text. | |
| 230 | +** Return a pointer to the combined header+body content. | |
| 181 | 231 | */ |
| 182 | 232 | char *cgi_extract_content(void){ |
| 183 | 233 | cgi_combine_header_and_body(); |
| 184 | 234 | return blob_buffer(&cgiContent[0]); |
| 185 | 235 | } |
| @@ -193,18 +243,25 @@ | ||
| 193 | 243 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 194 | 244 | static int rangeStart = 0; /* Start of Range: */ |
| 195 | 245 | static int rangeEnd = 0; /* End of Range: plus 1 */ |
| 196 | 246 | |
| 197 | 247 | /* |
| 198 | -** Set the reply content type | |
| 248 | +** Set the reply content type. | |
| 249 | +** | |
| 250 | +** The reply content type defaults to "text/html". It only needs to be | |
| 251 | +** changed (by calling this routine) in the exceptional case where some | |
| 252 | +** other content type is being returned. | |
| 199 | 253 | */ |
| 200 | 254 | void cgi_set_content_type(const char *zType){ |
| 201 | 255 | zContentType = fossil_strdup(zType); |
| 202 | 256 | } |
| 203 | 257 | |
| 204 | 258 | /* |
| 205 | -** Set the reply content to the specified BLOB. | |
| 259 | +** Erase any existing reply content. Replace is with a pNewContent. | |
| 260 | +** | |
| 261 | +** This routine erases pNewContent. In other words, it move pNewContent | |
| 262 | +** into the content buffer. | |
| 206 | 263 | */ |
| 207 | 264 | void cgi_set_content(Blob *pNewContent){ |
| 208 | 265 | cgi_reset_content(); |
| 209 | 266 | cgi_destination(CGI_HEADER); |
| 210 | 267 | cgiContent[0] = *pNewContent; |
| @@ -218,11 +275,11 @@ | ||
| 218 | 275 | zReplyStatus = fossil_strdup(zStat); |
| 219 | 276 | iReplyStatus = iStat; |
| 220 | 277 | } |
| 221 | 278 | |
| 222 | 279 | /* |
| 223 | -** Append text to the header of an HTTP reply | |
| 280 | +** Append text to the content header buffer. | |
| 224 | 281 | */ |
| 225 | 282 | void cgi_append_header(const char *zLine){ |
| 226 | 283 | blob_append(&extraHeader, zLine, -1); |
| 227 | 284 | } |
| 228 | 285 | void cgi_printf_header(const char *zLine, ...){ |
| @@ -278,11 +335,16 @@ | ||
| 278 | 335 | || sqlite3_strglob("application/*xml", zContentType)==0 |
| 279 | 336 | || sqlite3_strglob("application/*javascript", zContentType)==0; |
| 280 | 337 | } |
| 281 | 338 | |
| 282 | 339 | /* |
| 283 | -** Do a normal HTTP reply | |
| 340 | +** Generate the reply to a web request. The output might be an | |
| 341 | +** full HTTP response, or a CGI response, depending on how things have | |
| 342 | +** be set up. | |
| 343 | +** | |
| 344 | +** The reply consists of a response header (an HTTP or CGI response header) | |
| 345 | +** followed by the concatenation of the content header and content body. | |
| 284 | 346 | */ |
| 285 | 347 | void cgi_reply(void){ |
| 286 | 348 | Blob hdr = BLOB_INITIALIZER; |
| 287 | 349 | int total_size; |
| 288 | 350 | if( iReplyStatus<=0 ){ |
| @@ -409,11 +471,12 @@ | ||
| 409 | 471 | backoffice_check_if_needed(); |
| 410 | 472 | } |
| 411 | 473 | } |
| 412 | 474 | |
| 413 | 475 | /* |
| 414 | -** Do a redirect request to the URL given in the argument. | |
| 476 | +** Generate an HTTP or CGI redirect response that causes a redirect | |
| 477 | +** to the URL given in the argument. | |
| 415 | 478 | ** |
| 416 | 479 | ** The URL must be relative to the base of the fossil server. |
| 417 | 480 | */ |
| 418 | 481 | NORETURN void cgi_redirect_with_status( |
| 419 | 482 | const char *zURL, |
| @@ -474,11 +537,11 @@ | ||
| 474 | 537 | fossil_free(z); |
| 475 | 538 | } |
| 476 | 539 | |
| 477 | 540 | /* |
| 478 | 541 | ** Return the URL for the caller. This is obtained from either the |
| 479 | -** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter. | |
| 542 | +** "referer" CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter. | |
| 480 | 543 | ** If neither exist, return zDefault. |
| 481 | 544 | */ |
| 482 | 545 | const char *cgi_referer(const char *zDefault){ |
| 483 | 546 | const char *zRef = P("referer"); |
| 484 | 547 | if( zRef==0 ){ |
| @@ -510,12 +573,12 @@ | ||
| 510 | 573 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 511 | 574 | return 1; |
| 512 | 575 | } |
| 513 | 576 | |
| 514 | 577 | /* |
| 515 | -** Information about all query parameters and cookies are stored | |
| 516 | -** in these variables. | |
| 578 | +** Information about all query parameters, post parameter, cookies and | |
| 579 | +** CGI environment variables are stored in a hash table as follows: | |
| 517 | 580 | */ |
| 518 | 581 | static int nAllocQP = 0; /* Space allocated for aParamQP[] */ |
| 519 | 582 | static int nUsedQP = 0; /* Space actually used in aParamQP[] */ |
| 520 | 583 | static int sortQP = 0; /* True if aParamQP[] needs sorting */ |
| 521 | 584 | static int seqQP = 0; /* Sequence numbers */ |
| @@ -649,12 +712,12 @@ | ||
| 649 | 712 | } |
| 650 | 713 | } |
| 651 | 714 | } |
| 652 | 715 | |
| 653 | 716 | /* |
| 654 | -** Add a query parameter. The zName portion is fixed but a copy | |
| 655 | -** must be made of zValue. | |
| 717 | +** Add an environment varaible value to the parameter set. The zName | |
| 718 | +** portion is fixed but a copy is be made of zValue. | |
| 656 | 719 | */ |
| 657 | 720 | void cgi_setenv(const char *zName, const char *zValue){ |
| 658 | 721 | cgi_set_parameter_nocopy(zName, fossil_strdup(zValue), 0); |
| 659 | 722 | } |
| 660 | 723 | |
| 661 | 724 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -13,16 +13,53 @@ | |
| 13 | ** [email protected] |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains C functions and procedures used by CGI programs |
| 19 | ** (Fossil launched as CGI) to interpret CGI environment variables, |
| 20 | ** gather the results, and send they reply back to the CGI server. |
| 21 | ** This file also contains routines for running a simple web-server |
| 22 | ** (the "fossil ui" or "fossil server" command) and launching subprocesses |
| 23 | ** to handle each inbound HTTP request using CGI. |
| 24 | ** |
| 25 | ** This file contains routines used by Fossil when it is acting as a |
| 26 | ** CGI client. For the code used by Fossil when it is acting as a |
| 27 | ** CGI server (for the /ext webpage) see the "extcgi.c" source file. |
| 28 | */ |
| @@ -92,16 +129,27 @@ | |
| 92 | #define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */ |
| 93 | |
| 94 | #endif /* INTERFACE */ |
| 95 | |
| 96 | /* |
| 97 | ** The HTTP reply is generated in two pieces: the header and the body. |
| 98 | ** These pieces are generated separately because they are not necessarily |
| 99 | ** produced in order. Parts of the header might be built after all or |
| 100 | ** part of the body. The header and body are accumulated in separate |
| 101 | ** Blob structures then output sequentially once everything has been |
| 102 | ** built. |
| 103 | ** |
| 104 | ** The cgi_destination() interface switches between the buffers. |
| 105 | */ |
| 106 | static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER }; |
| 107 | static Blob *pContent = &cgiContent[0]; |
| @@ -124,51 +172,53 @@ | |
| 124 | } |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /* |
| 129 | ** Check to see if the header contains the zNeedle string. Return true |
| 130 | ** if it does and false if it does not. |
| 131 | */ |
| 132 | int cgi_header_contains(const char *zNeedle){ |
| 133 | return strstr(blob_str(&cgiContent[0]), zNeedle)!=0; |
| 134 | } |
| 135 | int cgi_body_contains(const char *zNeedle){ |
| 136 | return strstr(blob_str(&cgiContent[1]), zNeedle)!=0; |
| 137 | } |
| 138 | |
| 139 | /* |
| 140 | ** Append reply content to what already exists. |
| 141 | */ |
| 142 | void cgi_append_content(const char *zData, int nAmt){ |
| 143 | blob_append(pContent, zData, nAmt); |
| 144 | } |
| 145 | |
| 146 | /* |
| 147 | ** Reset the HTTP reply text to be an empty string. |
| 148 | */ |
| 149 | void cgi_reset_content(void){ |
| 150 | blob_reset(&cgiContent[0]); |
| 151 | blob_reset(&cgiContent[1]); |
| 152 | } |
| 153 | |
| 154 | /* |
| 155 | ** Return a pointer to the CGI output blob. |
| 156 | */ |
| 157 | Blob *cgi_output_blob(void){ |
| 158 | return pContent; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** Return complete text of the output header |
| 163 | */ |
| 164 | const char *cgi_header(void){ |
| 165 | return blob_str(&cgiContent[0]); |
| 166 | } |
| 167 | |
| 168 | /* |
| 169 | ** Combine the header and body of the CGI into a single string. |
| 170 | */ |
| 171 | static void cgi_combine_header_and_body(void){ |
| 172 | int size = blob_size(&cgiContent[1]); |
| 173 | if( size>0 ){ |
| 174 | blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size); |
| @@ -175,11 +225,11 @@ | |
| 175 | blob_reset(&cgiContent[1]); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | /* |
| 180 | ** Return a pointer to the HTTP reply text. |
| 181 | */ |
| 182 | char *cgi_extract_content(void){ |
| 183 | cgi_combine_header_and_body(); |
| 184 | return blob_buffer(&cgiContent[0]); |
| 185 | } |
| @@ -193,18 +243,25 @@ | |
| 193 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 194 | static int rangeStart = 0; /* Start of Range: */ |
| 195 | static int rangeEnd = 0; /* End of Range: plus 1 */ |
| 196 | |
| 197 | /* |
| 198 | ** Set the reply content type |
| 199 | */ |
| 200 | void cgi_set_content_type(const char *zType){ |
| 201 | zContentType = fossil_strdup(zType); |
| 202 | } |
| 203 | |
| 204 | /* |
| 205 | ** Set the reply content to the specified BLOB. |
| 206 | */ |
| 207 | void cgi_set_content(Blob *pNewContent){ |
| 208 | cgi_reset_content(); |
| 209 | cgi_destination(CGI_HEADER); |
| 210 | cgiContent[0] = *pNewContent; |
| @@ -218,11 +275,11 @@ | |
| 218 | zReplyStatus = fossil_strdup(zStat); |
| 219 | iReplyStatus = iStat; |
| 220 | } |
| 221 | |
| 222 | /* |
| 223 | ** Append text to the header of an HTTP reply |
| 224 | */ |
| 225 | void cgi_append_header(const char *zLine){ |
| 226 | blob_append(&extraHeader, zLine, -1); |
| 227 | } |
| 228 | void cgi_printf_header(const char *zLine, ...){ |
| @@ -278,11 +335,16 @@ | |
| 278 | || sqlite3_strglob("application/*xml", zContentType)==0 |
| 279 | || sqlite3_strglob("application/*javascript", zContentType)==0; |
| 280 | } |
| 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 ){ |
| @@ -409,11 +471,12 @@ | |
| 409 | backoffice_check_if_needed(); |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | /* |
| 414 | ** Do a redirect request to the URL given in the argument. |
| 415 | ** |
| 416 | ** The URL must be relative to the base of the fossil server. |
| 417 | */ |
| 418 | NORETURN void cgi_redirect_with_status( |
| 419 | const char *zURL, |
| @@ -474,11 +537,11 @@ | |
| 474 | fossil_free(z); |
| 475 | } |
| 476 | |
| 477 | /* |
| 478 | ** Return the URL for the caller. This is obtained from either the |
| 479 | ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter. |
| 480 | ** If neither exist, return zDefault. |
| 481 | */ |
| 482 | const char *cgi_referer(const char *zDefault){ |
| 483 | const char *zRef = P("referer"); |
| 484 | if( zRef==0 ){ |
| @@ -510,12 +573,12 @@ | |
| 510 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 511 | return 1; |
| 512 | } |
| 513 | |
| 514 | /* |
| 515 | ** Information about all query parameters and cookies are stored |
| 516 | ** in these variables. |
| 517 | */ |
| 518 | static int nAllocQP = 0; /* Space allocated for aParamQP[] */ |
| 519 | static int nUsedQP = 0; /* Space actually used in aParamQP[] */ |
| 520 | static int sortQP = 0; /* True if aParamQP[] needs sorting */ |
| 521 | static int seqQP = 0; /* Sequence numbers */ |
| @@ -649,12 +712,12 @@ | |
| 649 | } |
| 650 | } |
| 651 | } |
| 652 | |
| 653 | /* |
| 654 | ** Add a query parameter. The zName portion is fixed but a copy |
| 655 | ** must be made of zValue. |
| 656 | */ |
| 657 | void cgi_setenv(const char *zName, const char *zValue){ |
| 658 | cgi_set_parameter_nocopy(zName, fossil_strdup(zValue), 0); |
| 659 | } |
| 660 | |
| 661 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -13,16 +13,53 @@ | |
| 13 | ** [email protected] |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file began as a set of C functions and procedures used intepret |
| 19 | ** CGI environment variables for Fossil web pages that were invoked by |
| 20 | ** CGI. That's where the file name comes from. But over the years it |
| 21 | ** has grown to incorporate lots of related functionality, including: |
| 22 | ** |
| 23 | ** * Interpreting CGI environment variables when Fossil is run as |
| 24 | ** CGI (the original purpose). |
| 25 | ** |
| 26 | ** * Interpreting HTTP requests received directly or via an SSH tunnel. |
| 27 | ** |
| 28 | ** * Interpreting SCGI requests |
| 29 | ** |
| 30 | ** * Generating appropriate replies to CGI, SCGI, and HTTP requests. |
| 31 | ** |
| 32 | ** * Listening for incoming HTTP requests and dispatching them. |
| 33 | ** (Used by "fossil ui" and "fossil server", for example). |
| 34 | ** |
| 35 | ** So, even though the name of this file implies that it only deals with |
| 36 | ** CGI, in fact, the code in this file is used to interpret webpage requests |
| 37 | ** received by a variety of means, and to generate well-formatted replies |
| 38 | ** to those requests. |
| 39 | ** |
| 40 | ** The code in this file abstracts the web-request so that downstream |
| 41 | ** modules that generate the body of the reply (based on the requested page) |
| 42 | ** do not need to know if the request is coming from CGI, direct HTTP, |
| 43 | ** SCGI, or some other means. |
| 44 | ** |
| 45 | ** This module gathers information about web page request into a key/value |
| 46 | ** store. Keys and values come from: |
| 47 | ** |
| 48 | ** * Query parameters |
| 49 | ** * POST parameter |
| 50 | ** * Cookies |
| 51 | ** * Environment variables |
| 52 | ** |
| 53 | ** The parameters are accessed using cgi_parameter() and similar functions |
| 54 | ** or their convenience macros P() and similar. |
| 55 | ** |
| 56 | ** Environment variable parameters are set as if the request were coming |
| 57 | ** in over CGI even if the request arrived via SCGI or direct HTTP. Thus |
| 58 | ** the downstream modules that are trying to interpret the request do not |
| 59 | ** need to know the request protocol - they can just request the values |
| 60 | ** of environment variables and everything will always work. |
| 61 | ** |
| 62 | ** This file contains routines used by Fossil when it is acting as a |
| 63 | ** CGI client. For the code used by Fossil when it is acting as a |
| 64 | ** CGI server (for the /ext webpage) see the "extcgi.c" source file. |
| 65 | */ |
| @@ -92,16 +129,27 @@ | |
| 129 | #define CGI_SSH_FOSSIL 0x0004 /* Use new Fossil SSH transport */ |
| 130 | |
| 131 | #endif /* INTERFACE */ |
| 132 | |
| 133 | /* |
| 134 | ** The reply content is generated in two pieces: the header and the body. |
| 135 | ** These pieces are generated separately because they are not necessarily |
| 136 | ** produced in order. Parts of the header might be built after all or |
| 137 | ** part of the body. The header and body are accumulated in separate |
| 138 | ** Blob structures then output sequentially once everything has been |
| 139 | ** built. |
| 140 | ** |
| 141 | ** Do not confuse the content header with the HTTP header. The content header |
| 142 | ** is generated by downstream code. The HTTP header is generated by the |
| 143 | ** cgi_reply() routine below. |
| 144 | ** |
| 145 | ** The content header and contenty body are *approximately* the <head> |
| 146 | ** element and the <body> elements for HTML replies. However this is only |
| 147 | ** approximate. The content header also includes parts of <body> that |
| 148 | ** show the banner and menu bar at the top of each page. Also note that |
| 149 | ** not all replies are HTML, but there can still be separate header and |
| 150 | ** body sections of the content. |
| 151 | ** |
| 152 | ** The cgi_destination() interface switches between the buffers. |
| 153 | */ |
| 154 | static Blob cgiContent[2] = { BLOB_INITIALIZER, BLOB_INITIALIZER }; |
| 155 | static Blob *pContent = &cgiContent[0]; |
| @@ -124,51 +172,53 @@ | |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | /* |
| 177 | ** Check to see if the content header or body contains the zNeedle string. |
| 178 | ** Return true if it does and false if it does not. |
| 179 | */ |
| 180 | int cgi_header_contains(const char *zNeedle){ |
| 181 | return strstr(blob_str(&cgiContent[0]), zNeedle)!=0; |
| 182 | } |
| 183 | int cgi_body_contains(const char *zNeedle){ |
| 184 | return strstr(blob_str(&cgiContent[1]), zNeedle)!=0; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | ** Append new reply content to what already exists. |
| 189 | */ |
| 190 | void cgi_append_content(const char *zData, int nAmt){ |
| 191 | blob_append(pContent, zData, nAmt); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** Reset both reply content buffers to be empty. |
| 196 | */ |
| 197 | void cgi_reset_content(void){ |
| 198 | blob_reset(&cgiContent[0]); |
| 199 | blob_reset(&cgiContent[1]); |
| 200 | } |
| 201 | |
| 202 | /* |
| 203 | ** Return a pointer to Blob that is currently accumulating reply content. |
| 204 | */ |
| 205 | Blob *cgi_output_blob(void){ |
| 206 | return pContent; |
| 207 | } |
| 208 | |
| 209 | /* |
| 210 | ** Return the content header as a text string |
| 211 | */ |
| 212 | const char *cgi_header(void){ |
| 213 | return blob_str(&cgiContent[0]); |
| 214 | } |
| 215 | |
| 216 | /* |
| 217 | ** Combine the header and body content all into the header buffer. |
| 218 | ** In other words, append the body content to the end of the header |
| 219 | ** content. |
| 220 | */ |
| 221 | static void cgi_combine_header_and_body(void){ |
| 222 | int size = blob_size(&cgiContent[1]); |
| 223 | if( size>0 ){ |
| 224 | blob_append(&cgiContent[0], blob_buffer(&cgiContent[1]), size); |
| @@ -175,11 +225,11 @@ | |
| 225 | blob_reset(&cgiContent[1]); |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Return a pointer to the combined header+body content. |
| 231 | */ |
| 232 | char *cgi_extract_content(void){ |
| 233 | cgi_combine_header_and_body(); |
| 234 | return blob_buffer(&cgiContent[0]); |
| 235 | } |
| @@ -193,18 +243,25 @@ | |
| 243 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 244 | static int rangeStart = 0; /* Start of Range: */ |
| 245 | static int rangeEnd = 0; /* End of Range: plus 1 */ |
| 246 | |
| 247 | /* |
| 248 | ** Set the reply content type. |
| 249 | ** |
| 250 | ** The reply content type defaults to "text/html". It only needs to be |
| 251 | ** changed (by calling this routine) in the exceptional case where some |
| 252 | ** other content type is being returned. |
| 253 | */ |
| 254 | void cgi_set_content_type(const char *zType){ |
| 255 | zContentType = fossil_strdup(zType); |
| 256 | } |
| 257 | |
| 258 | /* |
| 259 | ** Erase any existing reply content. Replace is with a pNewContent. |
| 260 | ** |
| 261 | ** This routine erases pNewContent. In other words, it move pNewContent |
| 262 | ** into the content buffer. |
| 263 | */ |
| 264 | void cgi_set_content(Blob *pNewContent){ |
| 265 | cgi_reset_content(); |
| 266 | cgi_destination(CGI_HEADER); |
| 267 | cgiContent[0] = *pNewContent; |
| @@ -218,11 +275,11 @@ | |
| 275 | zReplyStatus = fossil_strdup(zStat); |
| 276 | iReplyStatus = iStat; |
| 277 | } |
| 278 | |
| 279 | /* |
| 280 | ** Append text to the content header buffer. |
| 281 | */ |
| 282 | void cgi_append_header(const char *zLine){ |
| 283 | blob_append(&extraHeader, zLine, -1); |
| 284 | } |
| 285 | void cgi_printf_header(const char *zLine, ...){ |
| @@ -278,11 +335,16 @@ | |
| 335 | || sqlite3_strglob("application/*xml", zContentType)==0 |
| 336 | || sqlite3_strglob("application/*javascript", zContentType)==0; |
| 337 | } |
| 338 | |
| 339 | /* |
| 340 | ** Generate the reply to a web request. The output might be an |
| 341 | ** full HTTP response, or a CGI response, depending on how things have |
| 342 | ** be set up. |
| 343 | ** |
| 344 | ** The reply consists of a response header (an HTTP or CGI response header) |
| 345 | ** followed by the concatenation of the content header and content body. |
| 346 | */ |
| 347 | void cgi_reply(void){ |
| 348 | Blob hdr = BLOB_INITIALIZER; |
| 349 | int total_size; |
| 350 | if( iReplyStatus<=0 ){ |
| @@ -409,11 +471,12 @@ | |
| 471 | backoffice_check_if_needed(); |
| 472 | } |
| 473 | } |
| 474 | |
| 475 | /* |
| 476 | ** Generate an HTTP or CGI redirect response that causes a redirect |
| 477 | ** to the URL given in the argument. |
| 478 | ** |
| 479 | ** The URL must be relative to the base of the fossil server. |
| 480 | */ |
| 481 | NORETURN void cgi_redirect_with_status( |
| 482 | const char *zURL, |
| @@ -474,11 +537,11 @@ | |
| 537 | fossil_free(z); |
| 538 | } |
| 539 | |
| 540 | /* |
| 541 | ** Return the URL for the caller. This is obtained from either the |
| 542 | ** "referer" CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter. |
| 543 | ** If neither exist, return zDefault. |
| 544 | */ |
| 545 | const char *cgi_referer(const char *zDefault){ |
| 546 | const char *zRef = P("referer"); |
| 547 | if( zRef==0 ){ |
| @@ -510,12 +573,12 @@ | |
| 573 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 574 | return 1; |
| 575 | } |
| 576 | |
| 577 | /* |
| 578 | ** Information about all query parameters, post parameter, cookies and |
| 579 | ** CGI environment variables are stored in a hash table as follows: |
| 580 | */ |
| 581 | static int nAllocQP = 0; /* Space allocated for aParamQP[] */ |
| 582 | static int nUsedQP = 0; /* Space actually used in aParamQP[] */ |
| 583 | static int sortQP = 0; /* True if aParamQP[] needs sorting */ |
| 584 | static int seqQP = 0; /* Sequence numbers */ |
| @@ -649,12 +712,12 @@ | |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | |
| 716 | /* |
| 717 | ** Add an environment varaible value to the parameter set. The zName |
| 718 | ** portion is fixed but a copy is be made of zValue. |
| 719 | */ |
| 720 | void cgi_setenv(const char *zName, const char *zValue){ |
| 721 | cgi_set_parameter_nocopy(zName, fossil_strdup(zValue), 0); |
| 722 | } |
| 723 | |
| 724 |