Overview
SHA1 Hash: | 7351b6346d153f984d38ece87b52c222346ed3be |
---|---|
Date: | 2008-05-15 16:58:42 |
User: | drh |
Comment: | Add the "/doc" method on the server. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/db.c from [0644da6326] to [3bee800775].
@@ -111,10 +111,11 @@ sqlite3_commit_hook(g.db, db_verify_at_commit, 0); } nBegin++; } void db_end_transaction(int rollbackFlag){ + if( nBegin<=0 ) return; if( rollbackFlag ) doRollback = 1; nBegin--; if( nBegin==0 ){ int i; for(i=0; doRollback==0 && i<nCommitHook; i++){
Modified src/info.c from [60d6be822b] to [d6911c08c2].
@@ -789,10 +789,197 @@ content_get(rid, &content); @ %h(blob_str(&content)) @ </pre></blockquote> blob_reset(&content); style_footer(); +} + +/* +** Guess the mime-type of a document based on its name. +*/ +const char *mimetype_from_name(const char *zName){ + const char *z; + int i; + char zSuffix[20]; + static const struct { + const char *zSuffix; + const char *zMimetype; + } aMime[] = { + { "html", "text/html" }, + { "htm", "text/html" }, + { "wiki", "application/x-fossil-wiki" }, + { "txt", "text/plain" }, + { "jpg", "image/jpeg" }, + { "jpeg", "image/jpeg" }, + { "gif", "image/gif" }, + { "png", "image/png" }, + { "css", "text/css" }, + }; + + z = zName; + for(i=0; zName[i]; i++){ + if( zName[i]=='.' ) z = &zName[i+1]; + } + i = strlen(z); + if( i<sizeof(zSuffix)-1 ){ + strcpy(zSuffix, z); + for(i=0; zSuffix[i]; i++) zSuffix[i] = tolower(zSuffix[i]); + for(i=0; i<sizeof(aMime)/sizeof(aMime[0]); i++){ + if( strcmp(zSuffix, aMime[i].zSuffix)==0 ){ + return aMime[i].zMimetype; + } + } + } + return "application/x-fossil-artifact"; +} + +/* +** WEBPAGE: doc +** URL: /doc?name=BASELINE/PATH +** +** BASELINE can be either a baseline uuid prefix or magic words "tip" +** to me the most recently checked in baseline or "ckout" to mean the +** content of the local checkout, if any. PATH is the relative pathname +** of some file. This method returns the file content. +** +** If PATH matches the patterns *.wiki or *.txt then formatting content +** is added before returning the file. For all other names, the content +** is returned straight without any interpretation or processing. +*/ +void doc_page(void){ + const char *zName; /* Argument to the /doc page */ + const char *zMime; /* Document MIME type */ + int vid = 0; /* Artifact of baseline */ + int rid = 0; /* Artifact of file */ + int i; /* Loop counter */ + Blob filebody; /* Content of the documentation file */ + char zBaseline[UUID_SIZE+1]; /* Baseline UUID */ + + login_check_credentials(); + if( !g.okRead ){ login_needed(); return; } + zName = PD("name", "tip/index.wiki"); + for(i=0; zName[i] && zName[i]!='/'; i++){} + if( zName[i]==0 || i>UUID_SIZE ){ + goto doc_not_found; + } + memcpy(zBaseline, zName, i); + zBaseline[i] = 0; + zName += i; + while( zName[0]=='/' ){ zName++; } + if( !file_is_simple_pathname(zName) ){ + goto doc_not_found; + } + if( strcmp(zBaseline,"ckout")==0 ){ + /* Read from the local checkout */ + char *zFullpath; + db_must_be_within_tree(); + zFullpath = mprintf("%s/%s", g.zLocalRoot, zName); + if( !file_isfile(zFullpath) ){ + goto doc_not_found; + } + if( blob_read_from_file(&filebody, zFullpath)<0 ){ + goto doc_not_found; + } + }else{ + db_begin_transaction(); + if( strcmp(zBaseline,"tip")==0 ){ + vid = db_int(0, "SELECT objid FROM event WHERE type='ci'" + " ORDER BY mtime DESC LIMIT 1"); + }else{ + vid = name_to_rid(zBaseline); + } + + /* Create the baseline cache if it does not already exist */ + db_multi_exec( + "CREATE TABLE IF NOT EXISTS vcache(\n" + " vid INTEGER, -- baseline ID\n" + " fname TEXT, -- filename\n" + " rid INTEGER, -- artifact ID\n" + " UNIQUE(vid,fname,rid)\n" + ")" + ); + + /* Check to see if the documentation file artifact ID is contained + ** in the baseline cache */ + rid = db_int(0, "SELECT rid FROM vcache" + " WHERE vid=%d AND fname=%Q", vid, zName); + if( rid==0 && db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){ + goto doc_not_found; + } + + if( rid==0 ){ + Stmt s; + Blob baseline; + Manifest m; + + /* Add the vid baseline to the cache */ + if( db_int(0, "SELECT count(*) FROM vcache")>10000 ){ + db_multi_exec("DELETE FROM vcache"); + } + if( content_get(vid, &baseline)==0 ){ + goto doc_not_found; + } + if( manifest_parse(&m, &baseline)==0 || m.type!=CFTYPE_MANIFEST ){ + goto doc_not_found; + } + db_prepare(&s, + "INSERT INTO vcache(vid,fname,rid)" + " SELECT %d, :fname, rid FROM blob" + " WHERE uuid=:uuid", + vid + ); + for(i=0; i<m.nFile; i++){ + db_bind_text(&s, ":fname", m.aFile[i].zName); + db_bind_text(&s, ":uuid", m.aFile[i].zUuid); + db_step(&s); + db_reset(&s); + } + db_finalize(&s); + manifest_clear(&m); + + /* Try again to find the file */ + rid = db_int(0, "SELECT rid FROM vcache" + " WHERE vid=%d AND fname=%Q", vid, zName); + } + if( rid==0 ){ + goto doc_not_found; + } + + /* Get the file content */ + if( content_get(rid, &filebody)==0 ){ + goto doc_not_found; + } + db_end_transaction(0); + } + + /* The file is now contained in the filebody blob. Deliver the + ** file to the user + */ + zMime = mimetype_from_name(zName); + if( strcmp(zMime, "application/x-fossil-wiki")==0 ){ + style_header("Documentation"); + wiki_convert(&filebody, 0, 0); + style_footer(); + }else if( strcmp(zMime, "text/plain")==0 ){ + style_header("Documentation"); + @ <blockquote><pre> + @ %h(blob_str(&filebody)) + @ </pre></blockquote> + style_footer(); + }else{ + cgi_set_content_type(zMime); + cgi_set_content(&filebody); + } + return; + +doc_not_found: + /* Jump here when unable to locate the document */ + db_end_transaction(0); + style_header("Document Not Found"); + @ <p>No such document: %h(PD("name","tip/index.wiki"))</p> + style_footer(); + return; } /* ** WEBPAGE: info ** URL: info/UUID
Modified src/wikiformat.c from [30a93b7778] to [2f33e8ac29].
@@ -151,12 +151,12 @@ #define MARKUP_H3 18 #define MARKUP_H4 19 #define MARKUP_H5 20 #define MARKUP_H6 21 #define MARKUP_HR 22 -#define MARKUP_IMG 23 -#define MARKUP_I 24 +#define MARKUP_I 23 +#define MARKUP_IMG 24 #define MARKUP_KBD 25 #define MARKUP_LI 26 #define MARKUP_NOBR 27 #define MARKUP_NOWIKI 28 #define MARKUP_OL 29 @@ -233,14 +233,14 @@ { "h4", MARKUP_H4, MUTYPE_BLOCK, ATTR_ALIGN }, { "h5", MARKUP_H5, MUTYPE_BLOCK, ATTR_ALIGN }, { "h6", MARKUP_H6, MUTYPE_BLOCK, ATTR_ALIGN }, { "hr", MARKUP_HR, MUTYPE_SINGLE, ATTR_ALIGN|ATTR_COLOR|ATTR_SIZE|ATTR_WIDTH }, + { "i", MARKUP_I, MUTYPE_FONT, 0 }, { "img", MARKUP_IMG, MUTYPE_SINGLE, ATTR_ALIGN|ATTR_ALT|ATTR_BORDER|ATTR_HEIGHT| ATTR_HSPACE|ATTR_SRC|ATTR_VSPACE|ATTR_WIDTH }, - { "i", MARKUP_I, MUTYPE_FONT, 0 }, { "kbd", MARKUP_KBD, MUTYPE_FONT, 0 }, { "li", MARKUP_LI, MUTYPE_LI, ATTR_TYPE|ATTR_VALUE }, { "nobr", MARKUP_NOBR, MUTYPE_FONT, 0 }, { "nowiki", MARKUP_NOWIKI, MUTYPE_SPECIAL, 0 },