/* ** Copyright (c) 2014 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains built-in string and BLOB resources packaged as ** byte arrays. */ #include "config.h" #include "builtin.h" #include /* ** The resources provided by this file are packaged by the "mkbuiltin.c" ** utility program during the built process and stored in the ** builtin_data.h file. Include that information here: */ #include "builtin_data.h" /* ** Return the index in the aBuiltinFiles[] array for the file ** whose name is zFilename. Or return -1 if the file is not ** found. */ static int builtin_file_index(const char *zFilename){ int lwr, upr, i, c; lwr = 0; upr = count(aBuiltinFiles) - 1; while( upr>=lwr ){ i = (upr+lwr)/2; c = strcmp(aBuiltinFiles[i].zName,zFilename); if( c<0 ){ lwr = i+1; }else if( c>0 ){ upr = i-1; }else{ return i; } } return -1; } /* ** Return a pointer to built-in content */ const unsigned char *builtin_file(const char *zFilename, int *piSize){ int i = builtin_file_index(zFilename); if( i>=0 ){ if( piSize ) *piSize = aBuiltinFiles[i].nByte; return aBuiltinFiles[i].pData; }else{ if( piSize ) *piSize = 0; return 0; } } const char *builtin_text(const char *zFilename){ return (char*)builtin_file(zFilename, 0); } /* ** COMMAND: test-builtin-list ** ** If -verbose is used, it outputs a line at the end ** with the total item count and size. ** ** List the names and sizes of all built-in resources. */ void test_builtin_list(void){ int i, size = 0;; for(i=0; i for(i=0; i%z(zUrl)%h(z) } @ style_footer(); } /* ** COMMAND: test-builtin-get ** ** Usage: %fossil test-builtin-get NAME ?OUTPUT-FILE? */ void test_builtin_get(void){ const unsigned char *pData; int nByte; Blob x; if( g.argc!=3 && g.argc!=4 ){ usage("NAME ?OUTPUT-FILE?"); } pData = builtin_file(g.argv[2], &nByte); if( pData==0 ){ fossil_fatal("no such built-in file: [%s]", g.argv[2]); } blob_init(&x, (const char*)pData, nByte); blob_write_to_file(&x, g.argc==4 ? g.argv[3] : "-"); blob_reset(&x); } /* ** Input zList is a list of numeric identifiers for files in ** aBuiltinFiles[]. Return the concatenation of all of those ** files using mimetype zType, or as application/javascript if ** zType is 0. */ static void builtin_deliver_multiple_js_files( const char *zList, /* List of numeric identifiers */ const char *zType /* Override mimetype */ ){ Blob *pOut; if( zType==0 ) zType = "application/javascript"; cgi_set_content_type(zType); pOut = cgi_output_blob(); while( zList[0] ){ int i = atoi(zList); if( i>0 && i<=count(aBuiltinFiles) ){ blob_append(pOut, (const char*)aBuiltinFiles[i-1].pData, aBuiltinFiles[i-1].nByte); } while( fossil_isdigit(zList[0]) ) zList++; if( zList[0]==',' ) zList++; } return; } /* ** WEBPAGE: builtin ** ** Return one of many built-in content files. Query parameters: ** ** name=FILENAME Return the single file whose name is FILENAME. ** mimetype=TYPE Override the mimetype in the returned file to ** be TYPE. If this query parameter is omitted ** (the usual case) then the mimetype is inferred ** from the suffix on FILENAME ** m=IDLIST IDLIST is a comma-separated list of integers ** that specify multiple javascript files to be ** concatenated and returned all at once. ** id=UNIQUEID Version number of the "builtin" files. Used ** for cache control only. ** ** At least one of the name= or m= query parameters must be present. ** ** If the id= query parameter is present, then Fossil assumes that the ** result is immutable and sets a very large cache retention time (1 year). */ void builtin_webpage(void){ Blob out; const char *zName = P("name"); const char *zTxt = 0; const char *zId = P("id"); const char *zType = P("mimetype"); int nId; if( zName ) zTxt = builtin_text(zName); if( zTxt==0 ){ const char *zM = P("m"); if( zM ){ builtin_deliver_multiple_js_files(zM, zType); return; } cgi_set_status(404, "Not Found"); @ File "%h(zName)" not found return; } if( zType==0 ){ if( sqlite3_strglob("*.js", zName)==0 ){ zType = "application/javascript"; }else{ zType = mimetype_from_name(zName); } } cgi_set_content_type(zType); if( zId && (nId = (int)strlen(zId))>=8 && strncmp(zId,fossil_exe_id(),nId)==0 ){ g.isConst = 1; }else{ etag_check(0,0); } blob_init(&out, zTxt, -1); cgi_set_content(&out); } /* Variables controlling the JS cache. */ static struct { int aReq[30]; /* Indexes of all requested built-in JS files */ int nReq; /* Number of slots in aReq[] currently used */ int nSent; /* Number of slots in aReq[] fulfilled */ int eDelivery; /* Delivery mechanism */ } builtin; #if INTERFACE /* Various delivery mechanisms. The 0 option is the default. */ #define JS_INLINE 0 /* inline, batched together at end of file */ #define JS_SEPARATE 1 /* Separate HTTP request for each JS file */ #define JS_BUNDLED 2 /* One HTTP request to load all JS files */ /* concatenated together into a bundle */ #endif /* INTERFACE */ /* ** The argument is a request to change the javascript delivery mode. ** The argument is a string which is a command-line option or CGI ** parameter. Try to match it against one of the delivery options ** and set things up accordingly. Throw an error if no match unless ** bSilent is true. */ void builtin_set_js_delivery_mode(const char *zMode, int bSilent){ if( zMode==0 ) return; if( strcmp(zMode, "inline")==0 ){ builtin.eDelivery = JS_INLINE; }else if( strcmp(zMode, "separate")==0 ){ builtin.eDelivery = JS_SEPARATE; }else if( strcmp(zMode, "bundled")==0 ){ builtin.eDelivery = JS_BUNDLED; }else if( !bSilent ){ fossil_fatal("unknown javascript delivery mode \"%s\" - should be" " one of: inline separate bundled", zMode); } } /* ** The caller wants the Javascript file named by zFilename to be ** included in the generated page. Add the file to the queue of ** requested javascript resources, if it is not there already. ** ** The current implementation queues the file to be included in the ** output later. However, the caller should not depend on that ** behavior. In the future, this routine might decide to insert ** the requested javascript inline, immedaitely, or to insert ** a \n"); break; } case JS_BUNDLED: { if( builtin.nSent+1\n", blob_str(&aList)+1, fossil_exe_id()); blob_reset(&aList); break; } /* If there is only one JS file, fall through into the ** JS_SEPARATE case below. */ /*FALLTHROUGH*/ } case JS_SEPARATE: { /* Each JS file as a separate resource */ while( builtin.nSent\n", aBuiltinFiles[i].zName, fossil_exe_id()); } break; } } }