Fossil SCM

Add support for the Range: attribute in HTTP requests for the "fossil server" and "fossil http" commands.

drh 2020-03-15 18:35 trunk merge
Commit b6892ccdd6f8f62522c325decdf2fe0e535c1b9bdf4e0df3d6fb69e4fc79df96
2 files changed +33 -4 +33 -4
+33 -4
--- src/cgi.c
+++ src/cgi.c
@@ -178,10 +178,12 @@
178178
*/
179179
static const char *zContentType = "text/html"; /* Content type of the reply */
180180
static const char *zReplyStatus = "OK"; /* Reply status description */
181181
static int iReplyStatus = 200; /* Reply status code */
182182
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
183
+static int rangeStart = 0; /* Start of Range: */
184
+static int rangeEnd = 0; /* End of Range: plus 1 */
183185
184186
/*
185187
** Set the reply content type
186188
*/
187189
void cgi_set_content_type(const char *zType){
@@ -272,15 +274,22 @@
272274
iReplyStatus = 200;
273275
zReplyStatus = "OK";
274276
}
275277
276278
if( g.fullHttpReply ){
279
+ if( rangeEnd>0
280
+ && iReplyStatus==200
281
+ && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
282
+ ){
283
+ iReplyStatus = 206;
284
+ }
277285
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
278286
fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
279287
fprintf(g.httpOut, "Connection: close\r\n");
280288
fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
281289
}else{
290
+ assert( rangeEnd==0 );
282291
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
283292
}
284293
if( g.isConst ){
285294
/* isConst means that the reply is guaranteed to be invariant, even
286295
** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,12 @@
325334
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
326335
cgi_combine_header_and_body();
327336
blob_compress(&cgiContent[0], &cgiContent[0]);
328337
}
329338
330
- if( iReplyStatus != 304 ) {
331
- if( is_gzippable() ){
339
+ if( iReplyStatus!=304 ) {
340
+ if( is_gzippable() && iReplyStatus!=206 ){
332341
int i;
333342
gzip_begin(0);
334343
for( i=0; i<2; i++ ){
335344
int size = blob_size(&cgiContent[i]);
336345
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
@@ -339,10 +348,15 @@
339348
gzip_finish(&cgiContent[0]);
340349
fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
341350
fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
342351
}
343352
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
353
+ if( iReplyStatus==206 ){
354
+ fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
355
+ rangeStart, rangeEnd-1, total_size);
356
+ total_size = rangeEnd - rangeStart;
357
+ }
344358
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
345359
}else{
346360
total_size = 0;
347361
}
348362
fprintf(g.httpOut, "\r\n");
@@ -350,12 +364,20 @@
350364
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
351365
){
352366
int i, size;
353367
for(i=0; i<2; i++){
354368
size = blob_size(&cgiContent[i]);
355
- if( size>0 ){
356
- fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut);
369
+ if( size<=rangeStart ){
370
+ rangeStart -= size;
371
+ }else{
372
+ int n = size - rangeStart;
373
+ if( n>total_size ){
374
+ n = total_size;
375
+ }
376
+ fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut);
377
+ rangeStart = 0;
378
+ total_size -= n;
357379
}
358380
}
359381
}
360382
fflush(g.httpOut);
361383
CGIDEBUG(("-------- END cgi ---------\n"));
@@ -1658,10 +1680,17 @@
16581680
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
16591681
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
16601682
if( zIpAddr!=0 ){
16611683
g.zIpAddr = mprintf("%s", zIpAddr);
16621684
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
1685
+ }
1686
+ }else if( fossil_strcmp(zFieldName,"range:")==0 ){
1687
+ int x1 = 0;
1688
+ int x2 = 0;
1689
+ if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
1690
+ rangeStart = x1;
1691
+ rangeEnd = x2+1;
16631692
}
16641693
}
16651694
}
16661695
cgi_init();
16671696
cgi_trace(0);
16681697
--- 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,15 +274,22 @@
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{
 
282 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
283 }
284 if( g.isConst ){
285 /* isConst means that the reply is guaranteed to be invariant, even
286 ** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,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 +348,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 +364,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 +1680,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; /* Start of Range: */
184 static int rangeEnd = 0; /* End of Range: plus 1 */
185
186 /*
187 ** Set the reply content type
188 */
189 void cgi_set_content_type(const char *zType){
@@ -272,15 +274,22 @@
274 iReplyStatus = 200;
275 zReplyStatus = "OK";
276 }
277
278 if( g.fullHttpReply ){
279 if( rangeEnd>0
280 && iReplyStatus==200
281 && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
282 ){
283 iReplyStatus = 206;
284 }
285 fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
286 fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
287 fprintf(g.httpOut, "Connection: close\r\n");
288 fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
289 }else{
290 assert( rangeEnd==0 );
291 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
292 }
293 if( g.isConst ){
294 /* isConst means that the reply is guaranteed to be invariant, even
295 ** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,12 @@
334 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
335 cgi_combine_header_and_body();
336 blob_compress(&cgiContent[0], &cgiContent[0]);
337 }
338
339 if( iReplyStatus!=304 ) {
340 if( is_gzippable() && iReplyStatus!=206 ){
341 int i;
342 gzip_begin(0);
343 for( i=0; i<2; i++ ){
344 int size = blob_size(&cgiContent[i]);
345 if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
@@ -339,10 +348,15 @@
348 gzip_finish(&cgiContent[0]);
349 fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
350 fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
351 }
352 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
353 if( iReplyStatus==206 ){
354 fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
355 rangeStart, rangeEnd-1, total_size);
356 total_size = rangeEnd - rangeStart;
357 }
358 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
359 }else{
360 total_size = 0;
361 }
362 fprintf(g.httpOut, "\r\n");
@@ -350,12 +364,20 @@
364 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
365 ){
366 int i, size;
367 for(i=0; i<2; i++){
368 size = blob_size(&cgiContent[i]);
369 if( size<=rangeStart ){
370 rangeStart -= size;
371 }else{
372 int n = size - rangeStart;
373 if( n>total_size ){
374 n = total_size;
375 }
376 fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut);
377 rangeStart = 0;
378 total_size -= n;
379 }
380 }
381 }
382 fflush(g.httpOut);
383 CGIDEBUG(("-------- END cgi ---------\n"));
@@ -1658,10 +1680,17 @@
1680 }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
1681 const char *zIpAddr = cgi_accept_forwarded_for(zVal);
1682 if( zIpAddr!=0 ){
1683 g.zIpAddr = mprintf("%s", zIpAddr);
1684 cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
1685 }
1686 }else if( fossil_strcmp(zFieldName,"range:")==0 ){
1687 int x1 = 0;
1688 int x2 = 0;
1689 if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
1690 rangeStart = x1;
1691 rangeEnd = x2+1;
1692 }
1693 }
1694 }
1695 cgi_init();
1696 cgi_trace(0);
1697
+33 -4
--- src/cgi.c
+++ src/cgi.c
@@ -178,10 +178,12 @@
178178
*/
179179
static const char *zContentType = "text/html"; /* Content type of the reply */
180180
static const char *zReplyStatus = "OK"; /* Reply status description */
181181
static int iReplyStatus = 200; /* Reply status code */
182182
static Blob extraHeader = BLOB_INITIALIZER; /* Extra header text */
183
+static int rangeStart = 0; /* Start of Range: */
184
+static int rangeEnd = 0; /* End of Range: plus 1 */
183185
184186
/*
185187
** Set the reply content type
186188
*/
187189
void cgi_set_content_type(const char *zType){
@@ -272,15 +274,22 @@
272274
iReplyStatus = 200;
273275
zReplyStatus = "OK";
274276
}
275277
276278
if( g.fullHttpReply ){
279
+ if( rangeEnd>0
280
+ && iReplyStatus==200
281
+ && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
282
+ ){
283
+ iReplyStatus = 206;
284
+ }
277285
fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
278286
fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
279287
fprintf(g.httpOut, "Connection: close\r\n");
280288
fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
281289
}else{
290
+ assert( rangeEnd==0 );
282291
fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
283292
}
284293
if( g.isConst ){
285294
/* isConst means that the reply is guaranteed to be invariant, even
286295
** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,12 @@
325334
if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
326335
cgi_combine_header_and_body();
327336
blob_compress(&cgiContent[0], &cgiContent[0]);
328337
}
329338
330
- if( iReplyStatus != 304 ) {
331
- if( is_gzippable() ){
339
+ if( iReplyStatus!=304 ) {
340
+ if( is_gzippable() && iReplyStatus!=206 ){
332341
int i;
333342
gzip_begin(0);
334343
for( i=0; i<2; i++ ){
335344
int size = blob_size(&cgiContent[i]);
336345
if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
@@ -339,10 +348,15 @@
339348
gzip_finish(&cgiContent[0]);
340349
fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
341350
fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
342351
}
343352
total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
353
+ if( iReplyStatus==206 ){
354
+ fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
355
+ rangeStart, rangeEnd-1, total_size);
356
+ total_size = rangeEnd - rangeStart;
357
+ }
344358
fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
345359
}else{
346360
total_size = 0;
347361
}
348362
fprintf(g.httpOut, "\r\n");
@@ -350,12 +364,20 @@
350364
&& fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
351365
){
352366
int i, size;
353367
for(i=0; i<2; i++){
354368
size = blob_size(&cgiContent[i]);
355
- if( size>0 ){
356
- fwrite(blob_buffer(&cgiContent[i]), 1, size, g.httpOut);
369
+ if( size<=rangeStart ){
370
+ rangeStart -= size;
371
+ }else{
372
+ int n = size - rangeStart;
373
+ if( n>total_size ){
374
+ n = total_size;
375
+ }
376
+ fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut);
377
+ rangeStart = 0;
378
+ total_size -= n;
357379
}
358380
}
359381
}
360382
fflush(g.httpOut);
361383
CGIDEBUG(("-------- END cgi ---------\n"));
@@ -1658,10 +1680,17 @@
16581680
}else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
16591681
const char *zIpAddr = cgi_accept_forwarded_for(zVal);
16601682
if( zIpAddr!=0 ){
16611683
g.zIpAddr = mprintf("%s", zIpAddr);
16621684
cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
1685
+ }
1686
+ }else if( fossil_strcmp(zFieldName,"range:")==0 ){
1687
+ int x1 = 0;
1688
+ int x2 = 0;
1689
+ if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
1690
+ rangeStart = x1;
1691
+ rangeEnd = x2+1;
16631692
}
16641693
}
16651694
}
16661695
cgi_init();
16671696
cgi_trace(0);
16681697
--- 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,15 +274,22 @@
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{
 
282 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
283 }
284 if( g.isConst ){
285 /* isConst means that the reply is guaranteed to be invariant, even
286 ** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,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 +348,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 +364,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 +1680,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; /* Start of Range: */
184 static int rangeEnd = 0; /* End of Range: plus 1 */
185
186 /*
187 ** Set the reply content type
188 */
189 void cgi_set_content_type(const char *zType){
@@ -272,15 +274,22 @@
274 iReplyStatus = 200;
275 zReplyStatus = "OK";
276 }
277
278 if( g.fullHttpReply ){
279 if( rangeEnd>0
280 && iReplyStatus==200
281 && fossil_strcmp(P("REQUEST_METHOD"),"GET")==0
282 ){
283 iReplyStatus = 206;
284 }
285 fprintf(g.httpOut, "HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
286 fprintf(g.httpOut, "Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
287 fprintf(g.httpOut, "Connection: close\r\n");
288 fprintf(g.httpOut, "X-UA-Compatible: IE=edge\r\n");
289 }else{
290 assert( rangeEnd==0 );
291 fprintf(g.httpOut, "Status: %d %s\r\n", iReplyStatus, zReplyStatus);
292 }
293 if( g.isConst ){
294 /* isConst means that the reply is guaranteed to be invariant, even
295 ** after configuration changes and/or Fossil binary recompiles. */
@@ -325,12 +334,12 @@
334 if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){
335 cgi_combine_header_and_body();
336 blob_compress(&cgiContent[0], &cgiContent[0]);
337 }
338
339 if( iReplyStatus!=304 ) {
340 if( is_gzippable() && iReplyStatus!=206 ){
341 int i;
342 gzip_begin(0);
343 for( i=0; i<2; i++ ){
344 int size = blob_size(&cgiContent[i]);
345 if( size>0 ) gzip_step(blob_buffer(&cgiContent[i]), size);
@@ -339,10 +348,15 @@
348 gzip_finish(&cgiContent[0]);
349 fprintf(g.httpOut, "Content-Encoding: gzip\r\n");
350 fprintf(g.httpOut, "Vary: Accept-Encoding\r\n");
351 }
352 total_size = blob_size(&cgiContent[0]) + blob_size(&cgiContent[1]);
353 if( iReplyStatus==206 ){
354 fprintf(g.httpOut, "Content-Range: bytes %d-%d/%d\r\n",
355 rangeStart, rangeEnd-1, total_size);
356 total_size = rangeEnd - rangeStart;
357 }
358 fprintf(g.httpOut, "Content-Length: %d\r\n", total_size);
359 }else{
360 total_size = 0;
361 }
362 fprintf(g.httpOut, "\r\n");
@@ -350,12 +364,20 @@
364 && fossil_strcmp(P("REQUEST_METHOD"),"HEAD")!=0
365 ){
366 int i, size;
367 for(i=0; i<2; i++){
368 size = blob_size(&cgiContent[i]);
369 if( size<=rangeStart ){
370 rangeStart -= size;
371 }else{
372 int n = size - rangeStart;
373 if( n>total_size ){
374 n = total_size;
375 }
376 fwrite(blob_buffer(&cgiContent[i])+rangeStart, 1, n, g.httpOut);
377 rangeStart = 0;
378 total_size -= n;
379 }
380 }
381 }
382 fflush(g.httpOut);
383 CGIDEBUG(("-------- END cgi ---------\n"));
@@ -1658,10 +1680,17 @@
1680 }else if( fossil_strcmp(zFieldName,"x-forwarded-for:")==0 ){
1681 const char *zIpAddr = cgi_accept_forwarded_for(zVal);
1682 if( zIpAddr!=0 ){
1683 g.zIpAddr = mprintf("%s", zIpAddr);
1684 cgi_replace_parameter("REMOTE_ADDR", g.zIpAddr);
1685 }
1686 }else if( fossil_strcmp(zFieldName,"range:")==0 ){
1687 int x1 = 0;
1688 int x2 = 0;
1689 if( sscanf(zVal,"bytes=%d-%d",&x1,&x2)==2 && x1>=0 && x1<=x2 ){
1690 rangeStart = x1;
1691 rangeEnd = x2+1;
1692 }
1693 }
1694 }
1695 cgi_init();
1696 cgi_trace(0);
1697

Keyboard Shortcuts

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