Fossil

Check-in [322643ca]
Login

Check-in [322643ca]

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

Overview
Comment:Added support for client-configurable mimetypes as a versionable setting.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mimetypes-setting
Files: files | file ages | folders
SHA3-256: 322643cac8465e9e62295a8ffa375b378677b09c3a962b1556352d1152599d15
User & Date: stephan 2020-01-22 02:41:15
Context
2020-01-23
18:00
/mimetype_list page now outputs custom mimetypes using %h formatting instead of %s, per forum feedback. ... (check-in: 23a92a27 user: stephan tags: mimetypes-setting)
2020-01-22
02:41
Added support for client-configurable mimetypes as a versionable setting. ... (check-in: 322643ca user: stephan tags: mimetypes-setting)
00:44
Added missing APPNAME to Makefile.classic, as reported in the forum. ... (check-in: a6ee6add user: stephan tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/db.c.

3447
3448
3449
3450
3451
3452
3453





3454
3455
3456
3457
3458
3459
3460
** when running as a web-server, Fossil does not open the
** global configuration database.
*/
/*
** SETTING: max-upload       width=25 default=250000
** A limit on the size of uplink HTTP requests.
*/





/*
** SETTING: mtime-changes    boolean default=on
** Use file modification times (mtimes) to detect when
** files have been modified.  If disabled, all managed files
** are hashed to detect changes, which can be slow for large
** projects.
*/







>
>
>
>
>







3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
** when running as a web-server, Fossil does not open the
** global configuration database.
*/
/*
** SETTING: max-upload       width=25 default=250000
** A limit on the size of uplink HTTP requests.
*/
/*
** SETTING: mimetypes        width=40 versionable block-text
** A list of file extension-to-mimetype mappings, one per line.
** Note that extensions are compared case-insensitively.
*/
/*
** SETTING: mtime-changes    boolean default=on
** Use file modification times (mtimes) to detect when
** files have been modified.  If disabled, all managed files
** are hashed to detect changes, which can be slow for large
** projects.
*/

Changes to src/doc.c.

302
303
304
305
306
307
308









































































309
310
311
312
313
314
315
  for(i=1; i<count(aMime); i++){
    if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){
      fossil_panic("mimetypes out of sequence: %s before %s",
                   aMime[i-1].zSuffix, aMime[i].zSuffix);
    }
  }
}










































































/*
** Guess the mime-type of a document based on its name.
*/
const char *mimetype_from_name(const char *zName){
  const char *z;
  int i;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  for(i=1; i<count(aMime); i++){
    if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){
      fossil_panic("mimetypes out of sequence: %s before %s",
                   aMime[i-1].zSuffix, aMime[i].zSuffix);
    }
  }
}

/*
** Looks in the contents of the "mimetypes" setting for a suffix
** matching zSuffix. If found, it returns the configured value
** in memory owned by the app (i.e. do not free() it), else it
** returns 0.
*/
static const char *mimetype_from_name_custom(const char *zSuffix){
  static char * zList = 0;
  static char const * zEnd = 0;
  static int once = 0;
  char * z;
  int tokenizerState /* 0=expecting a key, 1=skip next token,
                     ** 2=accept next token */;
  if(once==0){
    once = 1; 
    zList = db_get("mimetypes",0);
    if(zList==0){
      return 0;
    }
    /* Initialize zList and transform it to simplify
       the main loop. */
    zEnd = zList + strlen(zList);
    for(z = zList; z<zEnd; ++z){
      if('\n'==*z) continue;
      else if(fossil_isspace(*z)){
        *z = 0;
      }else if(!(0x80 & *z)){
        *z = (char)fossil_tolower(*z);
      }
    }
  }else if(zList==0){
    return 0;
  }
  tokenizerState = 0;
  z = zList;
  while( z<zEnd ){
    if(*z==0){
      ++z;
      continue;
    }
    else if('\n'==*z){
      /* May happen on malformed inputs. Skip this record. */
      if(2==tokenizerState){
        /* We were expecting a value for a successful match
           here, but got no value. Bail out. */
        break;
      }else{
        tokenizerState = 0;
        ++z;
        continue;
      }
    }
    switch(tokenizerState){
      case 0: /* This is a file extension */
        if(strcmp(z,zSuffix)==0){
          tokenizerState = 2 /*Match: accept the next value. */;
        }else{
          tokenizerState = 1 /* No match: skip the next value */;
        }
        z += strlen(z);
        break;
      case 1: /* This is a value, but not a match. Skip it. */
        z += strlen(z);
        break;
      case 2: /* This is the value which matched the previous key */;
        return z;
      default:
        assert(!"cannot happen - invalid tokenizerState value.");
    }
  }
  return 0;
}

/*
** Guess the mime-type of a document based on its name.
*/
const char *mimetype_from_name(const char *zName){
  const char *z;
  int i;
331
332
333
334
335
336
337




338
339
340
341
342
343
344
  z = zName;
  for(i=0; zName[i]; i++){
    if( zName[i]=='.' ) z = &zName[i+1];
  }
  len = strlen(z);
  if( len<sizeof(zSuffix)-1 ){
    sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);




    for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
    first = 0;
    last = count(aMime) - 1;
    while( first<=last ){
      int c;
      i = (first+last)/2;
      c = fossil_strcmp(zSuffix, aMime[i].zSuffix);







>
>
>
>







404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  z = zName;
  for(i=0; zName[i]; i++){
    if( zName[i]=='.' ) z = &zName[i+1];
  }
  len = strlen(z);
  if( len<sizeof(zSuffix)-1 ){
    sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z);
    z = mimetype_from_name_custom(zSuffix);
    if(z!=0){
      return z;
    }
    for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]);
    first = 0;
    last = count(aMime) - 1;
    while( first<=last ){
      int c;
      i = (first+last)/2;
      c = fossil_strcmp(zSuffix, aMime[i].zSuffix);
363
364
365
366
367
368
369

370
371
372
373
374
375
376
377
378
379
380
381
382

383
384
385
386
387
388
389
390
391
392
393
394
395
396
397

398










399
400
401
402
403
404
405
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void mimetype_test_cmd(void){
  int i;
  mimetype_verify();

  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*
** WEBPAGE: mimetype_list
**
** Show the built-in table used to guess embedded document mimetypes
** from file suffixes.
*/
void mimetype_list_page(void){
  int i;

  mimetype_verify();
  style_header("Mimetype List");
  @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
  @ suffixes and the following table to guess at the appropriate mimetype
  @ for each document.</p>
  @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
  @ data-column-types='tt' data-init-sort='1'>
  @ <thead>
  @ <tr><th>Suffix<th>Mimetype
  @ </thead>
  @ <tbody>
  for(i=0; i<count(aMime); i++){
    @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
  }
  @ </tbody></table>

  style_table_sorter();










  style_footer();
}

/*
** Check to see if the file in the pContent blob is "embedded HTML".  Return
** true if it is, and fill pTitle with the document title.
**







>













>















>
|
>
>
>
>
>
>
>
>
>
>







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test"
** filename is special and verifies the integrity of the mimetype table.
** It should return "ok".
*/
void mimetype_test_cmd(void){
  int i;
  mimetype_verify();
  db_find_and_open_repository(0, 0);
  for(i=2; i<g.argc; i++){
    fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i]));
  }
}

/*
** WEBPAGE: mimetype_list
**
** Show the built-in table used to guess embedded document mimetypes
** from file suffixes.
*/
void mimetype_list_page(void){
  int i;
  char * zCustomList = 0;
  mimetype_verify();
  style_header("Mimetype List");
  @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
  @ suffixes and the following table to guess at the appropriate mimetype
  @ for each document.</p>
  @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
  @ data-column-types='tt' data-init-sort='1'>
  @ <thead>
  @ <tr><th>Suffix<th>Mimetype
  @ </thead>
  @ <tbody>
  for(i=0; i<count(aMime); i++){
    @ <tr><td>%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
  }
  @ </tbody></table>
  zCustomList = db_get("mimetypes",0);
  if(zCustomList!=0){
    /* TODO: render this as a table, rather than a TEXTAREA.  That
    ** requires tokenizing the input, though, duplicating much of the
    ** work done in mimetype_from_name_custom().
    */
    @ <h1>Repo-specific mimetypes</h1>
    @ The following extention-to-mimetype mappings are defined via the
    @ <a href="%R/help?cmd=mimetypes">mimetypes setting</a>:<br>
    @ <textarea rows='10' cols='40' readonly>%s(zCustomList)</textarea>
    fossil_free(zCustomList);
  }
  style_footer();
}

/*
** Check to see if the file in the pContent blob is "embedded HTML".  Return
** true if it is, and fill pTitle with the document title.
**