Fossil SCM
Experimental support for "Range:" headers in HTTP requests.
Commit
37c615ad29935b47c91aacca9deed1a704e9534a1553ff04c89870731a870d17
Parent
54d93954a9848d6…
1 file changed
+29
-4
+29
-4
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -178,10 +178,12 @@ | ||
| 178 | 178 | */ |
| 179 | 179 | static const char *zContentType = "text/html"; /* Content type of the reply */ |
| 180 | 180 | static const char *zReplyStatus = "OK"; /* Reply status description */ |
| 181 | 181 | static int iReplyStatus = 200; /* Reply status code */ |
| 182 | 182 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 183 | +static int rangeStart = 0; | |
| 184 | +static int rangeEnd = 0; | |
| 183 | 185 | |
| 184 | 186 | /* |
| 185 | 187 | ** Set the reply content type |
| 186 | 188 | */ |
| 187 | 189 | void cgi_set_content_type(const char *zType){ |
| @@ -272,10 +274,13 @@ | ||
| 272 | 274 | iReplyStatus = 200; |
| 273 | 275 | zReplyStatus = "OK"; |
| 274 | 276 | } |
| 275 | 277 | |
| 276 | 278 | if( g.fullHttpReply ){ |
| 279 | + if( rangeEnd>rangeStart && iReplyStatus==200 ){ | |
| 280 | + iReplyStatus = 206; | |
| 281 | + } | |
| 277 | 282 | fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus); |
| 278 | 283 | fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0))); |
| 279 | 284 | fprintf(g.httpOut, "Connection: close\r\n"); |
| 280 | 285 | fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n"); |
| 281 | 286 | }else{ |
| @@ -325,12 +330,12 @@ | ||
| 325 | 330 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 326 | 331 | cgi_combine_header_and_body(); |
| 327 | 332 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 328 | 333 | } |
| 329 | 334 | |
| 330 | - if( iReplyStatus != 304 ) { | |
| 331 | - if( is_gzippable() ){ | |
| 335 | + if( iReplyStatus!=304 ) { | |
| 336 | + if( is_gzippable() && iReplyStatus!=206 ){ | |
| 332 | 337 | int i; |
| 333 | 338 | gzip_begin(0); |
| 334 | 339 | for( i=0; i<2; i++ ){ |
| 335 | 340 | int size = blob_size(&cgiContent[i]); |
| 336 | 341 | if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size); |
| @@ -339,10 +344,15 @@ | ||
| 339 | 344 | gzip_finish(&cgiContent[0]); |
| 340 | 345 | fprintf(g.httpOut, "Content-Encoding: gzip\r\n"); |
| 341 | 346 | fprintf(g.httpOut, "Vary: Accept-Encoding\r\n"); |
| 342 | 347 | } |
| 343 | 348 | total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]); |
| 349 | + if( iReplyStatus==206 ){ | |
| 350 | + fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n", | |
| 351 | + rangeStart, rangeEnd, total_size); | |
| 352 | + total_size = rangeEnd - rangeStart; | |
| 353 | + } | |
| 344 | 354 | fprintf(g.httpOut, "Content-Length: %d\r\n", total_size); |
| 345 | 355 | }else{ |
| 346 | 356 | total_size = 0; |
| 347 | 357 | } |
| 348 | 358 | fprintf(g.httpOut, "\r\n"); |
| @@ -350,12 +360,20 @@ | ||
| 350 | 360 | && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0 |
| 351 | 361 | ){ |
| 352 | 362 | int i, size; |
| 353 | 363 | for(i=0; i<2; i++){ |
| 354 | 364 | size = blob_size(&cgiContent[i]); |
| 355 | - if( size>0 ){ | |
| 356 | - fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); | |
| 365 | + if( size<=rangeStart ){ | |
| 366 | + rangeStart -= size; | |
| 367 | + }else{ | |
| 368 | + int n = size - rangeStart; | |
| 369 | + if( n>total_size ){ | |
| 370 | + n = total_size; | |
| 371 | + } | |
| 372 | + fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut); | |
| 373 | + rangeStart = 0; | |
| 374 | + total_size -= n; | |
| 357 | 375 | } |
| 358 | 376 | } |
| 359 | 377 | } |
| 360 | 378 | fflush(g.httpOut); |
| 361 | 379 | CGIDEBUG(("-------- END cgi ---------\n")); |
| @@ -1658,10 +1676,17 @@ | ||
| 1658 | 1676 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1659 | 1677 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1660 | 1678 | if( zIpAddr!=0 ){ |
| 1661 | 1679 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1662 | 1680 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1681 | + } | |
| 1682 | + }else if( fossil_strcmp(zFieldName,"range:")==0 ){ | |
| 1683 | + int x1 = 0; | |
| 1684 | + int x2 = 0; | |
| 1685 | + if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){ | |
| 1686 | + rangeStart = x1; | |
| 1687 | + rangeEnd = x2+1; | |
| 1663 | 1688 | } |
| 1664 | 1689 | } |
| 1665 | 1690 | } |
| 1666 | 1691 | cgi_init(); |
| 1667 | 1692 | cgi_trace(0); |
| 1668 | 1693 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -178,10 +178,12 @@ | |
| 178 | */ |
| 179 | static const char *zContentType = "text/html"; /* Content type of the reply */ |
| 180 | static const char *zReplyStatus = "OK"; /* Reply status description */ |
| 181 | static int iReplyStatus = 200; /* Reply status code */ |
| 182 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 183 | |
| 184 | /* |
| 185 | ** Set the reply content type |
| 186 | */ |
| 187 | void cgi_set_content_type(const char *zType){ |
| @@ -272,10 +274,13 @@ | |
| 272 | iReplyStatus = 200; |
| 273 | zReplyStatus = "OK"; |
| 274 | } |
| 275 | |
| 276 | if( g.fullHttpReply ){ |
| 277 | fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus); |
| 278 | fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0))); |
| 279 | fprintf(g.httpOut, "Connection: close\r\n"); |
| 280 | fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n"); |
| 281 | }else{ |
| @@ -325,12 +330,12 @@ | |
| 325 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 326 | cgi_combine_header_and_body(); |
| 327 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 328 | } |
| 329 | |
| 330 | if( iReplyStatus != 304 ) { |
| 331 | if( is_gzippable() ){ |
| 332 | int i; |
| 333 | gzip_begin(0); |
| 334 | for( i=0; i<2; i++ ){ |
| 335 | int size = blob_size(&cgiContent[i]); |
| 336 | if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size); |
| @@ -339,10 +344,15 @@ | |
| 339 | gzip_finish(&cgiContent[0]); |
| 340 | fprintf(g.httpOut, "Content-Encoding: gzip\r\n"); |
| 341 | fprintf(g.httpOut, "Vary: Accept-Encoding\r\n"); |
| 342 | } |
| 343 | total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]); |
| 344 | fprintf(g.httpOut, "Content-Length: %d\r\n", total_size); |
| 345 | }else{ |
| 346 | total_size = 0; |
| 347 | } |
| 348 | fprintf(g.httpOut, "\r\n"); |
| @@ -350,12 +360,20 @@ | |
| 350 | && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0 |
| 351 | ){ |
| 352 | int i, size; |
| 353 | for(i=0; i<2; i++){ |
| 354 | size = blob_size(&cgiContent[i]); |
| 355 | if( size>0 ){ |
| 356 | fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut); |
| 357 | } |
| 358 | } |
| 359 | } |
| 360 | fflush(g.httpOut); |
| 361 | CGIDEBUG(("-------- END cgi ---------\n")); |
| @@ -1658,10 +1676,17 @@ | |
| 1658 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1659 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1660 | if( zIpAddr!=0 ){ |
| 1661 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1662 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1663 | } |
| 1664 | } |
| 1665 | } |
| 1666 | cgi_init(); |
| 1667 | cgi_trace(0); |
| 1668 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -178,10 +178,12 @@ | |
| 178 | */ |
| 179 | static const char *zContentType = "text/html"; /* Content type of the reply */ |
| 180 | static const char *zReplyStatus = "OK"; /* Reply status description */ |
| 181 | static int iReplyStatus = 200; /* Reply status code */ |
| 182 | static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */ |
| 183 | static int rangeStart = 0; |
| 184 | static int rangeEnd = 0; |
| 185 | |
| 186 | /* |
| 187 | ** Set the reply content type |
| 188 | */ |
| 189 | void cgi_set_content_type(const char *zType){ |
| @@ -272,10 +274,13 @@ | |
| 274 | iReplyStatus = 200; |
| 275 | zReplyStatus = "OK"; |
| 276 | } |
| 277 | |
| 278 | if( g.fullHttpReply ){ |
| 279 | if( rangeEnd>rangeStart && iReplyStatus==200 ){ |
| 280 | iReplyStatus = 206; |
| 281 | } |
| 282 | fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus); |
| 283 | fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0))); |
| 284 | fprintf(g.httpOut, "Connection: close\r\n"); |
| 285 | fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n"); |
| 286 | }else{ |
| @@ -325,12 +330,12 @@ | |
| 330 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 331 | cgi_combine_header_and_body(); |
| 332 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 333 | } |
| 334 | |
| 335 | if( iReplyStatus!=304 ) { |
| 336 | if( is_gzippable() && iReplyStatus!=206 ){ |
| 337 | int i; |
| 338 | gzip_begin(0); |
| 339 | for( i=0; i<2; i++ ){ |
| 340 | int size = blob_size(&cgiContent[i]); |
| 341 | if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size); |
| @@ -339,10 +344,15 @@ | |
| 344 | gzip_finish(&cgiContent[0]); |
| 345 | fprintf(g.httpOut, "Content-Encoding: gzip\r\n"); |
| 346 | fprintf(g.httpOut, "Vary: Accept-Encoding\r\n"); |
| 347 | } |
| 348 | total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]); |
| 349 | if( iReplyStatus==206 ){ |
| 350 | fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n", |
| 351 | rangeStart, rangeEnd, total_size); |
| 352 | total_size = rangeEnd - rangeStart; |
| 353 | } |
| 354 | fprintf(g.httpOut, "Content-Length: %d\r\n", total_size); |
| 355 | }else{ |
| 356 | total_size = 0; |
| 357 | } |
| 358 | fprintf(g.httpOut, "\r\n"); |
| @@ -350,12 +360,20 @@ | |
| 360 | && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0 |
| 361 | ){ |
| 362 | int i, size; |
| 363 | for(i=0; i<2; i++){ |
| 364 | size = blob_size(&cgiContent[i]); |
| 365 | if( size<=rangeStart ){ |
| 366 | rangeStart -= size; |
| 367 | }else{ |
| 368 | int n = size - rangeStart; |
| 369 | if( n>total_size ){ |
| 370 | n = total_size; |
| 371 | } |
| 372 | fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut); |
| 373 | rangeStart = 0; |
| 374 | total_size -= n; |
| 375 | } |
| 376 | } |
| 377 | } |
| 378 | fflush(g.httpOut); |
| 379 | CGIDEBUG(("-------- END cgi ---------\n")); |
| @@ -1658,10 +1676,17 @@ | |
| 1676 | }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){ |
| 1677 | const char *zIpAddr = cgi_accept_forwarded_for(zVal); |
| 1678 | if( zIpAddr!=0 ){ |
| 1679 | g.zIpAddr = mprintf("%s", zIpAddr); |
| 1680 | cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr); |
| 1681 | } |
| 1682 | }else if( fossil_strcmp(zFieldName,"range:")==0 ){ |
| 1683 | int x1 = 0; |
| 1684 | int x2 = 0; |
| 1685 | if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){ |
| 1686 | rangeStart = x1; |
| 1687 | rangeEnd = x2+1; |
| 1688 | } |
| 1689 | } |
| 1690 | } |
| 1691 | cgi_init(); |
| 1692 | cgi_trace(0); |
| 1693 |