Fossil

Changes On Branch mimetypes-setting
Login

Changes On Branch mimetypes-setting

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

Changes In Branch mimetypes-setting Excluding Merge-Ins

This is equivalent to a diff from a6ee6add63 to 7391f8d486

2020-01-28
06:40
Merged in mimetypes-setting branch. ... (check-in: 009a24313b user: stephan tags: trunk)
2020-01-24
18:56
Added mimetypes setting to the 'project' configuration area, per forum feedback. ... (Closed-Leaf check-in: 7391f8d486 user: stephan tags: mimetypes-setting)
18:28
/mimetype_list: only show the custom mimetypes table if any are set. Add a link to the mimetypes setting help to the top of the page. Expanded the setting's help text. ... (check-in: 14d1b7a977 user: stephan tags: mimetypes-setting)
2020-01-22
19:08
Update the built-in SQLite to version 3.31.0. ... (check-in: eee161e823 user: drh tags: trunk)
02:41
Added support for client-configurable mimetypes as a versionable setting. ... (check-in: 322643cac8 user: stephan tags: mimetypes-setting)
00:44
Added missing APPNAME to Makefile.classic, as [https://fossil-scm.org/forum/forumpost/e51cc756b0|reported in the forum]. ... (check-in: a6ee6add63 user: stephan tags: trunk)
2020-01-20
20:29
Update the built-in SQLite to the second beta for 3.31.0, for SQLite testing. ... (check-in: f4e7ca02da user: drh tags: trunk)

Changes to src/configure.c.

141
142
143
144
145
146
147

148
149
150
151
152
153
154
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "dotfiles",               CONFIGSET_PROJ },
  { "parent-project-code",    CONFIGSET_PROJ },
  { "parent-project-name",    CONFIGSET_PROJ },
  { "hash-policy",            CONFIGSET_PROJ },
  { "comment-format",         CONFIGSET_PROJ },


#ifdef FOSSIL_ENABLE_LEGACY_MV_RM
  { "mv-rm-files",            CONFIGSET_PROJ },
#endif

  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },







>







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  { "empty-dirs",             CONFIGSET_PROJ },
  { "allow-symlinks",         CONFIGSET_PROJ },
  { "dotfiles",               CONFIGSET_PROJ },
  { "parent-project-code",    CONFIGSET_PROJ },
  { "parent-project-name",    CONFIGSET_PROJ },
  { "hash-policy",            CONFIGSET_PROJ },
  { "comment-format",         CONFIGSET_PROJ },
  { "mimetypes",              CONFIGSET_PROJ },

#ifdef FOSSIL_ENABLE_LEGACY_MV_RM
  { "mv-rm-files",            CONFIGSET_PROJ },
#endif

  { "ticket-table",           CONFIGSET_TKT  },
  { "ticket-common",          CONFIGSET_TKT  },

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
3466
3467
** 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. e.g.
** "foo application/x-foo". File extensions are compared
** case-insensitively in the order listed in this setting.  A leading
** '.' on file extensions is permitted but not required.
*/
/*
** 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
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  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.
**
** The mimetypes setting is expected to be a list of file extensions
** and mimetypes, with one such mapping per line. A leading '.'  on
** extensions is permitted for compatibility with lists imported from
** other tools which require them.
*/
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;
    }
    /* Transform zList to simplify the main loop:
       replace non-newline spaces with NUL bytes. */
    zEnd = zList + strlen(zList);
    for(z = zList; z<zEnd; ++z){
      if('\n'==*z) continue;
      else if(fossil_isspace(*z)){
        *z = 0;
      }
    }
  }else if(zList==0){
    return 0;
  }
  tokenizerState = 0;
  z = zList;
  while( z<zEnd ){
    if(*z==0){
      ++z;
      continue;
    }
    else if('\n'==*z){
      if(2==tokenizerState){
        /* We were expecting a value for a successful match
           here, but got no value. Bail out. */
        break;
      }else{
        /* May happen on malformed inputs. Skip this record. */
        tokenizerState = 0;
        ++z;
        continue;
      }
    }
    switch(tokenizerState){
      case 0:{ /* This is a file extension */
        static char * zCase = 0;
        if('.'==*z){
          /*ignore an optional leading dot, for compatibility
            with some external mimetype lists*/;
          if(++z==zEnd){
            break;
          }
        }
        if(zCase<z){
          /*we have not yet case-folded this section: lower-case it*/
          for(zCase = z; zCase<zEnd && *zCase!=0; ++zCase){
            if(!(0x80 & *zCase)){
              *zCase = (char)fossil_tolower(*zCase);
            }
          }
        }
        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;
332
333
334
335
336
337
338




339
340
341
342
343
344
345
  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);
      if( c==0 ) return aMime[i].zMimetype;







>
>
>
>







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  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]);
    z = mimetype_from_name_custom(zSuffix);
    if(z!=0){
      return z;
    }
    first = 0;
    last = count(aMime) - 1;
    while( first<=last ){
      int c;
      i = (first+last)/2;
      c = fossil_strcmp(zSuffix, aMime[i].zSuffix);
      if( c==0 ) return aMime[i].zMimetype;
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
** 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();
}

/*







>













>
>
>



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







>
>
>
>
>
|







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
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
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
** 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;    /* value of the mimetypes setting */
  int nCustomEntries = 0;   /* number of entries in the mimetypes
                            ** setting */
  mimetype_verify();
  style_header("Mimetype List");
  @ <p>The Fossil <a href="%R/help?cmd=/doc">/doc</a> page uses filename
  @ suffixes and the following tables to guess at the appropriate mimetype
  @ for each document. Mimetypes may be customized and overridden using
  @ <a href="%R/help?cmd=mimetypes">the mimetypes config setting</a>.</p>
  zCustomList = db_get("mimetypes",0);
  if( zCustomList!=0 ){
    Blob list, entry, key, val;
    @ <h1>Repository-specific mimetypes</h1>
    @ <p>The following extension-to-mimetype mappings are defined via
    @ the <a href="%R/help?cmd=mimetypes">mimetypes setting</a>.</p>
    @ <table class='sortable mimetypetable' border=1 cellpadding=0 \
    @ data-column-types='tt' data-init-sort='0'>
    @ <thead>
    @ <tr><th>Suffix<th>Mimetype
    @ </thead>
    @ <tbody>
    blob_set(&list, zCustomList);
    while( blob_line(&list, &entry)>0 ){
      const char *zKey;
      if( blob_token(&entry, &key)==0 ) continue;
      if( blob_token(&entry, &val)==0 ) continue;
      zKey = blob_str(&key);
      if( zKey[0]=='.' ) zKey++;
      @ <tr><td>%h(zKey)<td>%h(blob_str(&val))</tr>
      nCustomEntries++;
    }
    fossil_free(zCustomList);
    if( nCustomEntries==0 ){
      /* This can happen if the option is set to an empty/space-only
      ** value. */
      @ <tr><td colspan="2"><em>none</em></tr>
    }
    @ </tbody></table>
  }
  @ <h1>Default built-in mimetypes</h1>
  if(nCustomEntries>0){
    @ <p>Entries starting with an exclamation mark <em><strong>!</strong></em>
    @ are overwritten by repository-specific settings.</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++){
    const char *zFlag = "";
    if(nCustomEntries>0 &&
       mimetype_from_name_custom(aMime[i].zSuffix)!=0){
      zFlag = "<em><strong>!</strong></em> ";
    }
    @ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr>
  }
  @ </tbody></table>
  style_table_sorter();
  style_footer();
}

/*