Fossil with Commonmark

Changes On Branch short-cgi-params
Login

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

Changes In Branch short-cgi-params Excluding Merge-Ins

This is equivalent to a diff from e09d84f297 to e89269e51b

2013-05-02
19:44
Fix --chdir on Windows/Cygwin when using non-ascii characters or characters invalid for win32 filenames. On Cygwin, allow enter_chroot_jail() using win32 paths as well. check-in: 12bc63aae5 user: jan.nijtmans tags: trunk
15:04
rebase Closed-Leaf check-in: 9e4a7190af user: jan.nijtmans tags: clean-with-ignore
13:52
rebase Closed-Leaf check-in: e89269e51b user: jan.nijtmans tags: short-cgi-params
13:28
Allow boolean parameters sbs= and v= to taken values like "on", "off", "yes", and "no". Assign meaningful defaults even if the argument is omitted. check-in: e09d84f297 user: drh tags: trunk
07:58
See alternative implementation on trunk. Was: Improve cgi parameter parsing in add_param_list(). Boolean options, like "v" and "sbs" can now take forms like "v=true" or simply "v" (in stead of "v=1") or "v=off" (in stead of "v=0"). /timeline already accepted the shortened form, now /event, /vdiff and other web pages do as well. check-in: 71d48d346c user: jan.nijtmans tags: short-cgi-params
00:15
Keep the entry boxes filled in on the hash-color-test webpage. check-in: 8d3ff5a710 user: drh tags: trunk

Changes to src/cgi.c.

256
257
258
259
260
261
262
263

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

263
264
265
266
267
268
269
270







-
+







      for( zTok = strtok_r(zBuf, ",\"",&zPos);
           zTok && fossil_stricmp(zTok,zETag);
           zTok =  strtok_r(0, ",\"",&zPos)){}
      fossil_free(zBuf);
      if(zTok) return 1;
    }
  }
  

  return 0;
}
#endif

/*
** Do a normal HTTP reply
*/
463
464
465
466
467
468
469
470

471
472
473
474
475
476
477
463
464
465
466
467
468
469

470
471
472
473
474
475
476
477







-
+







/*
** Add a query parameter.  The zName portion is fixed but a copy
** must be made of zValue.
*/
void cgi_setenv(const char *zName, const char *zValue){
  cgi_set_parameter_nocopy(zName, mprintf("%s",zValue));
}
 


/*
** Add a list of query parameters or cookies to the parameter set.
**
** Each parameter is of the form NAME=VALUE.  Both the NAME and the
** VALUE may be url-encoded ("+" for space, "%HH" for other special
** characters).  But this routine assumes that NAME contains no
496
497
498
499
500
501
502

503
504
505






506
507

508
509
510
511
512




513
514
515
516

517
518
519
520
521
522
523
496
497
498
499
500
501
502
503



504
505
506
507
508
509


510





511
512
513
514
515
516


517
518
519
520
521
522
523
524







+
-
-
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
+
+
+
+


-
-
+







*/
static void add_param_list(char *z, int terminator){
  while( *z ){
    char *zName;
    char *zValue;
    while( fossil_isspace(*z) ){ z++; }
    zName = z;
    zValue = 0;
    while( *z && *z!='=' && *z!=terminator ){ z++; }
    if( *z=='=' ){
      *z = 0;
    while( *z ){
      if( *z==terminator ){
        *z++ = 0; break;
      }
      if( !zValue && (*z=='=') ){
        *z = 0;
      z++;
      zValue = z;
        zValue = z+1;
      while( *z && *z!=terminator ){ z++; }
      if( *z ){
        *z = 0;
        z++;
      }
      }
      z++;
    }
    if( zValue ){
      dehttpize(zValue);
    }else{
      if( *z ){ *z++ = 0; }
      zValue = "";
      zValue = zName;
    }
    if( fossil_islower(zName[0]) ){
      cgi_set_parameter_nocopy(zName, zValue);
    }
#ifdef FOSSIL_ENABLE_JSON
    json_setenv( zName, cson_value_new_string(zValue,strlen(zValue)) );
#endif /* FOSSIL_ENABLE_JSON */
580
581
582
583
584
585
586
587

588
589
590
591
592
593
594
581
582
583
584
585
586
587

588
589
590
591
592
593
594
595







-
+







      *pnContent = i;
      i += nBoundry;
      break;
    }
  }
  *pz = &z[i];
  get_line_from_string(pz, pLen);
  return z;      
  return z;
}

/*
** Tokenize a line of text into as many as nArg tokens.  Make
** azArg[] point to the start of each token.
**
** Tokens consist of space or semi-colon delimited words or
687
688
689
690
691
692
693
694

695
696
697
698
699
700
701
688
689
690
691
692
693
694

695
696
697
698
699
700
701
702







-
+







          char *z = azArg[++i];
          if( zName && z && fossil_islower(zName[0]) ){
            cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z);
          }
        }
      }
    }
  }        
  }
}


#ifdef FOSSIL_ENABLE_JSON
/*
** Internal helper for cson_data_source_FILE_n().
*/
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
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







-
+















-
+







  cgi_destination(CGI_BODY);

  z = (char*)P("HTTP_COOKIE");
  if( z ){
    z = mprintf("%s",z);
    add_param_list(z, ';');
  }
  

  z = (char*)P("QUERY_STRING");
  if( z ){
    z = mprintf("%s",z);
    add_param_list(z, '&');
  }

  z = (char*)P("REMOTE_ADDR");
  if( z ){
    g.zIpAddr = mprintf("%s", z);
  }

  len = atoi(PD("CONTENT_LENGTH", "0"));
  g.zContentType = zType = P("CONTENT_TYPE");
  if( len>0 && zType ){
    blob_zero(&g.cgiIn);
    if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0 
    if( fossil_strcmp(zType,"application/x-www-form-urlencoded")==0
         || strncmp(zType,"multipart/form-data",19)==0 ){
      z = fossil_malloc( len+1 );
      len = fread(z, 1, len, g.httpIn);
      z[len] = 0;
      cgi_trace(z);
      if( zType[0]=='a' ){
        add_param_list(z, '&');
877
878
879
880
881
882
883
884

885
886
887
888
889
890
891
878
879
880
881
882
883
884

885
886
887
888
889
890
891
892







-
+







      g.json.isJsonMode = 1;
      cgi_parse_POST_JSON(g.httpIn, (unsigned int)len);
      /* FIXMEs:

      - See if fossil really needs g.cgiIn to be set for this purpose
      (i don't think it does). If it does then fill g.cgiIn and
      refactor to parse the JSON from there.
      

      - After parsing POST JSON, copy the "first layer" of keys/values
      to cgi_setenv(), honoring the upper-case distinction used
      in add_param_list(). However...

      - If we do that then we might get a disconnect in precedence of
      GET/POST arguments. i prefer for GET entries to take precedence
      over like-named POST entries, but in order for that to happen we
1194
1195
1196
1197
1198
1199
1200
1201

1202
1203
1204
1205
1206

1207
1208
1209
1210

1211
1212
1213
1214
1215
1216
1217
1195
1196
1197
1198
1199
1200
1201

1202
1203
1204
1205
1206

1207
1208
1209
1210

1211
1212
1213
1214
1215
1216
1217
1218







-
+




-
+



-
+







  }
  cgi_setenv("REQUEST_URI", zToken);
  for(i=0; zToken[i] && zToken[i]!='?'; i++){}
  if( zToken[i] ) zToken[i++] = 0;
  cgi_setenv("PATH_INFO", zToken);
  cgi_setenv("QUERY_STRING", &zToken[i]);
  if( zIpAddr==0 &&
        getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, 
        getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName,
                                &size)>=0
  ){
    zIpAddr = inet_ntoa(remoteName.sin_addr);
  }
  if( zIpAddr ){   
  if( zIpAddr ){
    cgi_setenv("REMOTE_ADDR", zIpAddr);
    g.zIpAddr = mprintf("%s", zIpAddr);
  }
 

  /* Get all the optional fields that follow the first line.
  */
  while( fgets(zLine,sizeof(zLine),g.httpIn) ){
    char *zFieldName;
    char *zVal;

    cgi_trace(zLine);
1247
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260
1261
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260
1261
1262







-
+







    }
  }
  cgi_init();
  cgi_trace(0);
}

#if INTERFACE
/* 
/*
** Bitmap values for the flags parameter to cgi_http_server().
*/
#define HTTP_SERVER_LOCALHOST      0x0001     /* Bind to 127.0.0.1 only */

#endif /* INTERFACE */

/*
1383
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396
1397
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395
1396
1397
1398







-
+







      }
    }
    /* Bury dead children */
    while( waitpid(0, 0, WNOHANG)>0 ){
      nchildren--;
    }
  }
  /* NOT REACHED */  
  /* NOT REACHED */
  fossil_exit(1);
#endif
  /* NOT REACHED */
  return 0;
}


1471
1472
1473
1474
1475
1476
1477
1478

1479
1480
1481
1482
1483
1484
1485
1472
1473
1474
1475
1476
1477
1478

1479
1480
1481
1482
1483
1484
1485
1486







-
+







  }else if( p->tm_mon>11 ){
    p->tm_year += p->tm_mon/12;
    p->tm_mon %= 12;
  }
  isLeapYr = p->tm_year%4==0 && (p->tm_year%100!=0 || (p->tm_year+300)%400==0);
  p->tm_yday = priorDays[p->tm_mon] + p->tm_mday - 1;
  if( isLeapYr && p->tm_mon>1 ) p->tm_yday++;
  nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 + 
  nDay = (p->tm_year-70)*365 + (p->tm_year-69)/4 -p->tm_year/100 +
         (p->tm_year+300)/400 + p->tm_yday;
  t = ((nDay*24 + p->tm_hour)*60 + p->tm_min)*60 + p->tm_sec;
  return t;
}

/*
** Check the objectTime against the If-Modified-Since request header. If the

Changes to src/event.c.

183
184
185
186
187
188
189
190

191
192
193
194
195
196
197
183
184
185
186
187
188
189

190
191
192
193
194
195
196
197







-
+







      @ <div>
    }
    blob_init(&comment, pEvent->zComment, -1);
    wiki_convert(&comment, 0, WIKI_INLINE);
    blob_reset(&comment);
    @ </div>
    @ </blockquote><hr />
  }  
  }

  wiki_convert(&tail, 0, 0);
  style_footer();
  manifest_destroy(pEvent);
}

/*
225
226
227
228
229
230
231
232

233
234
235
236
237
238
239
225
226
227
228
229
230
231

232
233
234
235
236
237
238
239







-
+







    int nEventId = strlen(zEventId);
    if( nEventId!=40 || !validate16(zEventId, 40) ){
      fossil_redirect_home();
      return;
    }
  }
  zTag = mprintf("event-%s", zEventId);
  rid = db_int(0, 
  rid = db_int(0,
    "SELECT rid FROM tagxref"
    " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
    " ORDER BY mtime DESC", zTag
  );
  free(zTag);

  /* Need both check-in and wiki-write or wiki-create privileges in order
305
306
307
308
309
310
311
312

313
314
315
316
317
318
319
305
306
307
308
309
310
311

312
313
314
315
316
317
318
319







-
+







      Blob tags, one;
      int i, j;
      Stmt q;
      char *zBlob;

      /* Load the tags string into a blob */
      blob_zero(&tags);
      blob_append(&tags, zTags, -1); 
      blob_append(&tags, zTags, -1);

      /* Collapse all sequences of whitespace and "," characters into
      ** a single space character */
      zBlob = blob_str(&tags);
      for(i=j=0; zBlob[i]; i++, j++){
        if( fossil_isspace(zBlob[i]) || zBlob[i]==',' ){
          while( fossil_isspace(zBlob[i+1]) ){ i++; }
334
335
336
337
338
339
340
341

342
343
344
345
346
347
348
334
335
336
337
338
339
340

341
342
343
344
345
346
347
348







-
+







      /* Extract the tags in sorted order and make an entry in the
      ** artifact for each. */
      db_prepare(&q, "SELECT x FROM newtags ORDER BY x");
      while( db_step(&q)==SQLITE_ROW ){
        blob_appendf(&event, "T +sym-%F *\n", db_column_text(&q, 0));
      }
      db_finalize(&q);
    }        
    }
    if( g.zLogin ){
      blob_appendf(&event, "U %F\n", g.zLogin);
    }
    blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
    md5sum_blob(&event, &cksum);
    blob_appendf(&event, "Z %b\n", &cksum);
    blob_reset(&cksum);
404
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419

420
421
422
423
424

425
426
427

428
429
430
431
432
433
434
435
436
437
438
404
405
406
407
408
409
410

411
412
413
414
415
416
417
418

419
420
421
422
423

424
425
426

427
428
429
430
431
432
433
434
435
436
437
438







-
+







-
+




-
+


-
+











  @ <tr><td align="right" valign="top"><b>Event&nbsp;Time:</b></td>
  @ <td valign="top">
  @   <input type="text" name="t" size="25" value="%h(zETime)" />
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Timeline&nbsp;Comment:</b></td>
  @ <td valign="top">
  @ <textarea name="c" class="eventedit" cols="80" 
  @ <textarea name="c" class="eventedit" cols="80"
  @  rows="3" wrap="virtual">%h(zComment)</textarea>
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Background&nbsp;Color:</b></td>
  @ <td valign="top">
  render_color_chooser(0, zClr, 0, "clr", "cclr");
  @ </td></tr>
  

  @ <tr><td align="right" valign="top"><b>Tags:</b></td>
  @ <td valign="top">
  @   <input type="text" name="g" size="40" value="%h(zTags)" />
  @ </td></tr>
  

  @ <tr><td align="right" valign="top"><b>Page&nbsp;Content:</b></td>
  @ <td valign="top">
  @ <textarea name="w" class="eventedit" cols="80" 
  @ <textarea name="w" class="eventedit" cols="80"
  @  rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
  @ </td></tr>

  @ <tr><td colspan="2">
  @ <input type="submit" name="preview" value="Preview Your Changes" />
  @ <input type="submit" name="submit" value="Apply These Changes" />
  @ <input type="submit" name="cancel" value="Cancel" />
  @ </td></tr></table>
  @ </div></form>
  style_footer();
}

Changes to src/info.c.

388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
388
389
390
391
392
393
394

395
396
397
398
399
400
401
402







-
+







    }
    if( diffFlags ){
      @ <pre style="white-space:pre;">
      append_diff(zOld, zNew, diffFlags, pRe);
      @ </pre>
    }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
      @ &nbsp;&nbsp;
      @ %z(href("%R/fdiff?v1=%S&v2=%S",zOld,zNew))[diff]</a>
      @ %z(href("%R/fdiff?v1=%S&v2=%S&sbs=1",zOld,zNew))[diff]</a>
    }
    @ </p>
  }
}

/*
** Construct an appropriate diffFlag for text_diff() based on query
453
454
455
456
457
458
459

460
461
462
463
464
465
466
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467







+







  int verboseFlag;     /* True to show diffs */
  int sideBySide;      /* True for side-by-side diffs */
  u64 diffFlags;       /* Flag parameter for text_diff() */
  const char *zName;   /* Name of the checkin to be displayed */
  const char *zUuid;   /* UUID of zName */
  const char *zParent; /* UUID of the parent checkin (if any) */
  const char *zRe;     /* regex parameter */
  const char *zSbs;
  ReCompiled *pRe = 0; /* regex */

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  zName = P("name");
  rid = name_to_rid_www("name");
  if( rid==0 ){
482
483
484
485
486
487
488

489

490
491
492
493
494
495
496
483
484
485
486
487
488
489
490

491
492
493
494
495
496
497
498







+
-
+







     "SELECT uuid, datetime(mtime, 'localtime'), user, comment,"
     "       datetime(omtime, 'localtime'), mtime"
     "  FROM blob, event"
     " WHERE blob.rid=%d"
     "   AND event.objid=%d",
     rid, rid
  );
  zSbs = P("sbs"); /* Note that "sbs=1" is the default value */
  sideBySide = !is_false(PD("sbs","1"));
  sideBySide = (zSbs==0) || ((*zSbs!=0) && !is_false(zSbs));
  if( db_step(&q)==SQLITE_ROW ){
    const char *zUuid = db_column_text(&q, 0);
    char *zTitle = mprintf("Check-in [%.10s]", zUuid);
    char *zEUser, *zEComment;
    const char *zUser;
    const char *zComment;
    const char *zDate;
894
895
896
897
898
899
900

901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917

918

919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937

938
939
940
941
942

943
944
945
946
947
948
949
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921

922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940

941
942
943
944
945

946
947
948
949
950
951
952
953







+

















+
-
+


















-
+




-
+







  Manifest *pFrom, *pTo;
  ManifestFile *pFileFrom, *pFileTo;
  const char *zBranch;
  const char *zFrom;
  const char *zTo;
  const char *zRe;
  const char *zVerbose;
  const char *zSbs;
  ReCompiled *pRe = 0;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  login_anonymous_available();

  zRe = P("regex");
  if( zRe ) re_compile(&pRe, zRe, 0);
  zBranch = P("branch");
  if( zBranch && zBranch[0] ){
    cgi_replace_parameter("from", mprintf("root:%s", zBranch));
    cgi_replace_parameter("to", zBranch);
  }
  pTo = vdiff_parse_manifest("to", &ridTo);
  if( pTo==0 ) return;
  pFrom = vdiff_parse_manifest("from", &ridFrom);
  if( pFrom==0 ) return;
  zSbs = P("sbs"); /* Note that "sbs=1" is the default value */
  sideBySide = !is_false(PD("sbs","1"));
  sideBySide = (zSbs==0) || ((*zSbs!=0) && !is_false(zSbs));
  zVerbose = P("v");
  if( !zVerbose ){
    zVerbose = P("verbose");
  }
  if( !zVerbose ){
    zVerbose = P("detail"); /* deprecated */
  }
  verboseFlag = (zVerbose!=0) && (*zVerbose!=0) && !is_false(zVerbose);
  if( !verboseFlag && sideBySide ) verboseFlag = 1;
  zFrom = P("from");
  zTo = P("to");
  if( !sideBySide ){
    style_submenu_element("Side-by-side Diff", "sbsdiff",
                          "%R/vdiff?from=%T&to=%T&sbs=1",
                          zFrom, zTo);
  }
  if( sideBySide || !verboseFlag ) {
    style_submenu_element("Unified Diff", "udiff",
                          "%R/vdiff?from=%T&to=%T%s&sbs=0&v=1",
                          "%R/vdiff?from=%T&to=%T%s&sbs=0&v",
                          zFrom, zTo);
  }
  style_submenu_element("Invert", "invert",
                        "%R/vdiff?from=%T&to=%T&sbs=%d%s", zTo, zFrom,
                        sideBySide, (verboseFlag && !sideBySide)?"&v=1":"");
                        sideBySide, (verboseFlag && !sideBySide)?"&v":"");
  style_header("Check-in Differences");
  @ <h2>Difference From:</h2><blockquote>
  checkin_description(ridFrom);
  @ </blockquote><h2>To:</h2><blockquote>
  checkin_description(ridTo);
  @ </blockquote>
  if( pRe ){
1244
1245
1246
1247
1248
1249
1250
1251

1252
1253
1254
1255
1256
1257
1258
1259
1260

1261

1262
1263
1264
1265
1266
1267
1268
1248
1249
1250
1251
1252
1253
1254

1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265

1266
1267
1268
1269
1270
1271
1272
1273







-
+









+
-
+







void diff_page(void){
  int v1, v2;
  int isPatch;
  int sideBySide;
  Blob c1, c2, diff, *pOut;
  char *zV1;
  char *zV2;
  const char *zRe;
  const char *zRe, *zSbs;
  ReCompiled *pRe = 0;
  u64 diffFlags;
  const char *zStyle = "sbsdiff";

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  v1 = name_to_rid_www("v1");
  v2 = name_to_rid_www("v2");
  if( v1==0 || v2==0 ) fossil_redirect_home();
  zSbs = P("sbs"); /* Note that "sbs=1" is the default value */
  sideBySide = !is_false(PD("sbs","1"));
  sideBySide = (zSbs==0) || ((*zSbs!=0) && !is_false(zSbs));
  zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1);
  zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
  isPatch = P("patch")!=0;
  if( isPatch ){
    pOut = cgi_output_blob();
    cgi_set_content_type("text/plain");
    diffFlags = 4;