HTFWrite.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:13k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /*             HTFWrite.c
  2. ** FILE WRITER
  3. **
  4. ** (c) COPYRIGHT MIT 1995.
  5. ** Please first read the full copyright statement in the file COPYRIGH.
  6. **
  7. ** This version of the stream object just writes to a C file.
  8. ** The file is assumed open and left open.
  9. **
  10. ** Bugs:
  11. ** strings written must be less than buffer size.
  12. **
  13. **      History:
  14. **         HFN: wrote it
  15. **         HWL: converted the caching scheme to be hierachical by taking
  16. **              AL code from Deamon
  17. **    HFN: moved cache code to HTCache module
  18. **
  19. */
  20. /* Library include files */
  21. #include "tcp.h"
  22. #include "HTUtils.h"
  23. #include "HTString.h"
  24. #include "HTFormat.h"
  25. #include "HTError.h"
  26. #include "HTAlert.h"
  27. #include "HTAccess.h"
  28. #include "HTBind.h"
  29. #include "HTList.h"
  30. #include "HTParse.h"
  31. #include "HTReq.h"
  32. #include "HTFWrite.h"  /* Implemented here */
  33. #define HASH_SIZE 1001 /* Tunable */
  34. /* The default directory for "save locally" and "save and execute" files: */
  35. #ifndef HT_TMP_ROOT
  36. #define HT_TMP_ROOT "/tmp"
  37. #endif
  38. struct _HTStream {
  39.     CONST HTStreamClass *isa;
  40.     
  41.     FILE * fp;
  42.     BOOL leave_open;     /* Close file when free? */
  43.     char *  end_command;        /* Command to execute */
  44.     BOOL  remove_on_close;      /* Remove file? */
  45.     char * filename;      /* Name of file */
  46.     HTRequest * request;        /* saved for callback */
  47.     HTRequestCallback * callback;
  48. };
  49. PRIVATE HTStream HTBaseStreamInstance;       /* Made static */
  50. PRIVATE char * HTTmpRoot = NULL;           /* Dest for tmp files */
  51. /* ------------------------------------------------------------------------- */
  52. /*        BASIC STREAM CLASSES      */
  53. /* ------------------------------------------------------------------------- */
  54. /*
  55. **
  56. ** B L A C K    H O L E    C L A S S
  57. **
  58. ** There is only one black hole instance shared by anyone
  59. ** who wants a black hole.  These black holes don't radiate,
  60. ** they just absorb data.
  61. */
  62. PRIVATE int HTBlackHole_put_character (HTStream * me, char c)
  63. {
  64.     return HT_OK;
  65. }
  66. PRIVATE int HTBlackHole_put_string (HTStream * me, CONST char * s)
  67. {
  68.     return HT_OK;
  69. }
  70. PRIVATE int HTBlackHole_write (HTStream * me, CONST char * s, int l)
  71. {
  72.     return HT_OK;
  73. }
  74. PRIVATE int HTBlackHole_flush (HTStream * me)
  75. {
  76.     return HT_OK;
  77. }
  78. PRIVATE int HTBlackHole_free (HTStream * me)
  79. {
  80.     return HT_OK;
  81. }
  82. PRIVATE int HTBlackHole_abort (HTStream * me, HTList * e)
  83. {
  84.     return HT_ERROR;
  85. }
  86. /* Black Hole stream
  87. ** -----------------
  88. */
  89. PRIVATE CONST HTStreamClass HTBlackHoleClass =
  90. {
  91.     "BlackHole",
  92.     HTBlackHole_flush,
  93.     HTBlackHole_free,
  94.     HTBlackHole_abort,
  95.     HTBlackHole_put_character,
  96.     HTBlackHole_put_string,
  97.     HTBlackHole_write
  98. }; 
  99. PUBLIC HTStream * HTBlackHole (void)
  100. {
  101.     if (STREAM_TRACE) TTYPrint(TDEST, "BlackHole... Createdn");
  102.     HTBaseStreamInstance.isa = &HTBlackHoleClass;      /* The rest is random */
  103.     return &HTBaseStreamInstance;
  104. }
  105. PUBLIC HTStream * HTBlackHoleConverter (HTRequest * request,
  106. void * param,
  107. HTFormat input_format,
  108. HTFormat output_format,
  109. HTStream * output_stream)
  110. {
  111.     return HTBlackHole();
  112. }
  113. /*
  114. ** ERROR STREAM
  115. ** ------------
  116. ** There is only one error stream shared by anyone who wants a
  117. ** generic error returned from all stream methods.
  118. */
  119. PRIVATE int HTErrorStream_put_character (HTStream * me, char c)
  120. {
  121.     return HT_ERROR;
  122. }
  123. PRIVATE int HTErrorStream_put_string (HTStream * me, CONST char * s)
  124. {
  125.     return HT_ERROR;
  126. }
  127. PRIVATE int HTErrorStream_write (HTStream * me, CONST char * s, int l)
  128. {
  129.     return HT_ERROR;
  130. }
  131. PRIVATE int HTErrorStream_flush (HTStream * me)
  132. {
  133.     return HT_ERROR;
  134. }
  135. PRIVATE int HTErrorStream_free (HTStream * me)
  136. {
  137.     return HT_ERROR;
  138. }
  139. PRIVATE int HTErrorStream_abort (HTStream * me, HTList * e)
  140. {
  141.     return HT_ERROR;
  142. }
  143. PRIVATE CONST HTStreamClass HTErrorStreamClass =
  144. {
  145.     "ErrorStream",
  146.     HTErrorStream_flush,
  147.     HTErrorStream_free,
  148.     HTErrorStream_abort,
  149.     HTErrorStream_put_character,
  150.     HTErrorStream_put_string,
  151.     HTErrorStream_write
  152. }; 
  153. PUBLIC HTStream * HTErrorStream (void)
  154. {
  155.     if (STREAM_TRACE) TTYPrint(TDEST, "ErrorStream. Createdn");
  156.     HTBaseStreamInstance.isa = &HTErrorStreamClass;    /* The rest is random */
  157.     return &HTBaseStreamInstance;
  158. }
  159. /* HTThroughLine
  160. ** -------------
  161. **
  162. ** This function is a dummy function that returns the same output stream
  163. ** as given as a parameter. Henrik 01/03-94
  164. */
  165. PUBLIC HTStream* HTThroughLine (HTRequest * request,
  166. void * param,
  167. HTFormat input_format,
  168. HTFormat output_format,
  169. HTStream * output_stream)
  170. {
  171.     return output_stream;
  172. }
  173. /* ------------------------------------------------------------------------- */
  174. /*        SOCKET WRITER STREAM      */
  175. /* ------------------------------------------------------------------------- */
  176. PRIVATE int HTFWriter_put_character (HTStream * me, char c)
  177. {
  178.     return (fputc(c, me->fp) == EOF) ? HT_ERROR : HT_OK;
  179. }
  180. PRIVATE int HTFWriter_put_string (HTStream * me, CONST char* s)
  181. {
  182.     if (*s)              /* For vms :-( 10/04-94 */
  183. return (fputs(s, me->fp) == EOF) ? HT_ERROR : HT_OK;
  184.     return HT_OK;
  185. }
  186. PRIVATE int HTFWriter_flush (HTStream * me)
  187. {
  188.     return (fflush(me->fp) == EOF) ? HT_ERROR : HT_OK;
  189. }
  190. PRIVATE int HTFWriter_write (HTStream * me, CONST char* s, int l)
  191. {
  192.     int status ;
  193.     status = (fwrite(s, 1, l, me->fp) != l) ? HT_ERROR : HT_OK ;
  194.     if (l > 1 && status == HT_OK) (void) HTFWriter_flush(me);
  195.     return status ;
  196. }
  197. PRIVATE int HTFWriter_free (HTStream * me)
  198. {
  199.     if (me) {
  200. if (me->leave_open != YES) fclose(me->fp);
  201. #ifdef GOT_SYSTEM
  202. if (me->end_command) system(me->end_command);    /* SECURITY HOLE!!! */
  203. #endif
  204. if (me->remove_on_close) REMOVE(me->filename);
  205. if (me->callback) (*me->callback)(me->request, me->filename);
  206. HT_FREE(me->end_command);
  207. HT_FREE(me->filename);
  208. HT_FREE(me);
  209.     }
  210.     return HT_OK;
  211. }
  212. PRIVATE int HTFWriter_abort (HTStream * me, HTList * e)
  213. {
  214.     if (STREAM_TRACE) TTYPrint(TDEST, "FileWriter.. ABORTING...n");
  215.     if (me) {
  216. if (me->leave_open != YES) fclose(me->fp);
  217. if (me->remove_on_close) REMOVE(me->filename);
  218. HT_FREE(me->end_command);
  219. HT_FREE(me->filename);
  220. HT_FREE(me);
  221.     }
  222.     return HT_ERROR;
  223. }
  224. PRIVATE CONST HTStreamClass HTFWriter = /* As opposed to print etc */
  225. {
  226.     "FileWriter",
  227.     HTFWriter_flush,
  228.     HTFWriter_free,
  229.     HTFWriter_abort,
  230.     HTFWriter_put_character,
  231.     HTFWriter_put_string,
  232.     HTFWriter_write
  233. };
  234. PUBLIC HTStream * HTFWriter_new (HTRequest * request, FILE * fp,
  235.  BOOL leave_open)
  236. {
  237.     HTStream * me = NULL;
  238.     if (!fp) {
  239. if (STREAM_TRACE)TTYPrint(TDEST, "FileWriter.. Bad file descriptorn");
  240. return HTErrorStream();
  241.     }
  242.     if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
  243.         HT_OUTOFMEM("HTFWriter_new");
  244.     me->isa = &HTFWriter;       
  245.     me->fp = fp;
  246.     me->leave_open = leave_open;
  247.     me->request = request;
  248.     return me;
  249. }
  250. /* ------------------------------------------------------------------------- */
  251. /*        FILE WRITER ROUTINES      */
  252. /* ------------------------------------------------------------------------- */
  253. /* Set TMP Root
  254. ** --------------
  255. ** If `tmp_root' is NULL use the current value (might be a define)
  256. */
  257. PUBLIC BOOL HTTmp_setRoot (CONST char * tmp_root)
  258. {
  259.     StrAllocCopy(HTTmpRoot, tmp_root ? tmp_root : HT_TMP_ROOT);
  260.     if (*(HTTmpRoot+strlen(HTTmpRoot)-1) != '/')
  261. StrAllocCat(HTTmpRoot, "/");
  262.     if (STREAM_TRACE)
  263. TTYPrint(TDEST, "Tmp Root.... Root set to `%s'n", HTTmpRoot);
  264.     return YES;
  265. }
  266. /* Get Tmp Root
  267. ** --------------
  268. */
  269. PUBLIC CONST char * HTTmp_getRoot (void)
  270. {
  271.     return HTTmpRoot;
  272. }
  273. /* Free Tmp Root
  274. ** --------------
  275. ** For clean up memory
  276. */
  277. PUBLIC void HTTmp_freeRoot (void)
  278. {
  279.     HT_FREE(HTTmpRoot);
  280. }
  281. /*
  282. **   This function tries really hard to find a non-existent filename relative
  283. **   to the path given. Returns a string that must be freed by the caller or
  284. **   NULL on error. The base must be '/' terminated which!
  285. */
  286. PRIVATE char *get_filename (char * base, CONST char * url, CONST char * suffix)
  287. {
  288.     char *path=NULL;
  289.     char filename[40];
  290.     int hash=0;
  291.     /* Do this until we find a name that doesn't exist */
  292.     while (1)
  293.     {
  294. CONST char *ptr=url;
  295. for( ; *ptr; ptr++)
  296.     hash = (int) ((hash * 31 + (* (unsigned char *) ptr)) % HASH_SIZE);
  297. #ifndef NO_GETPID
  298. sprintf(filename, "%d-%d", hash, (int) getpid());
  299. #else
  300. sprintf(filename, "%d-%d", hash, time(NULL));
  301. #endif
  302. StrAllocCopy(path, base);
  303. StrAllocCat(path, filename);
  304. if (suffix) StrAllocCat(path, suffix);
  305. {
  306.     FILE *fp = fopen(path, "r");
  307.     if (fp)      /* This file does already exist */
  308. fclose(fp);
  309.     else
  310. break; /* Got the file name */
  311. }
  312.     }
  313.     return path;
  314. }
  315. /* Save Locally
  316. ** ------------
  317. ** Saves a file to local disk. This can for example be used to dump
  318. ** date objects of unknown media types to local disk. The stream prompts
  319. ** for a file name for the temporary file.
  320. */
  321. PUBLIC HTStream* HTSaveLocally (HTRequest * request,
  322. void * param,
  323. HTFormat input_format,
  324. HTFormat output_format,
  325. HTStream * output_stream)
  326. {
  327.     FILE * fp = NULL;
  328.     char * filename = NULL;
  329.     if (HTLib_secure()) {
  330. HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
  331.    NULL, 0, "HTSaveLocally");
  332. return HTErrorStream();
  333.     }
  334.     if (!HTTmpRoot) {
  335. if (STREAM_TRACE) TTYPrint(TDEST, "Save File... turned off");
  336. return HTErrorStream();
  337.     }
  338.     /* Let's prompt the user for a file name for this file */
  339.     {
  340. HTAlertCallback *cbf = HTAlert_find(HT_A_PROMPT);
  341. HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
  342. char *suffix = HTBind_getSuffix(anchor);
  343. char *deflt = get_filename(HTTmpRoot,HTAnchor_physical(anchor),suffix);
  344. if (cbf) {
  345.     HTAlertPar * reply = HTAlert_newReply();
  346.     if ((*cbf)(request, HT_A_PROMPT, HT_MSG_FILENAME,deflt,NULL,reply))
  347. filename = HTAlert_replyMessage(reply);
  348.     HTAlert_deleteReply(reply);
  349. }
  350. HT_FREE(suffix);
  351. HT_FREE(deflt);
  352. if (filename) {
  353.     if ((fp = fopen(filename, "wb")) == NULL) {
  354. HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
  355.    filename, strlen(filename),"HTSaveLocally");
  356. HT_FREE(filename);
  357. return HTErrorStream();
  358.     }
  359. } else {
  360.     if (STREAM_TRACE) TTYPrint(TDEST, "Save File... No file namen");
  361.     return HTErrorStream();
  362. }
  363.     }
  364.     
  365.     /* Now we are ready for creating the file writer stream */
  366.     if (fp) {
  367. HTStream * me = HTFWriter_new(request, fp, NO);
  368. me->filename = filename;
  369. return me;
  370.     }
  371.     HT_FREE(filename);
  372.     return HTErrorStream();
  373. }
  374. /* Take action using a system command
  375. ** ----------------------------------
  376. ** Creates temporary file, writes to it and then executes system
  377. ** command (maybe an external viewer) when EOF has been reached. The
  378. ** stream finds a suitable name of the temporary file which preserves the
  379. ** suffix. This way, the system command can find out the file type from
  380. ** the name of the temporary file name.
  381. */
  382. PUBLIC HTStream* HTSaveAndExecute (HTRequest * request,
  383.    void * param,
  384.    HTFormat input_format,
  385.    HTFormat output_format,
  386.    HTStream * output_stream)
  387. {
  388.     FILE * fp = NULL;
  389.     char * filename = NULL;
  390.     if (HTLib_secure()) {
  391. HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_UNAUTHORIZED,
  392.    NULL, 0, "HTSaveLocally");
  393. return HTErrorStream();
  394.     }
  395.     if (!HTTmpRoot) {
  396. if (STREAM_TRACE) TTYPrint(TDEST, "Save File... turned off");
  397. return HTErrorStream();
  398.     }
  399.     /* Let's find a hash name for this file without asking user */
  400.     {
  401. HTParentAnchor *anchor = (HTParentAnchor *) HTRequest_anchor(request);
  402. char *suffix = HTBind_getSuffix(anchor);
  403. filename = get_filename(HTTmpRoot, HTAnchor_physical(anchor), suffix);
  404. HT_FREE(suffix);
  405. if (filename) {
  406.     if ((fp = fopen(filename, "wb")) == NULL) {
  407. HTRequest_addError(request, ERR_NON_FATAL, NO, HTERR_NO_FILE,
  408.    filename, strlen(filename),"HTSaveAndExecute");
  409. HT_FREE(filename);
  410. return HTErrorStream();
  411.     }
  412. } else {
  413.     if (STREAM_TRACE) TTYPrint(TDEST, "Save File... No file namen");
  414.     return HTErrorStream();
  415. }
  416.     }
  417.     
  418.     /* Now we are ready for creating the file writer stream */
  419.     if (fp) {
  420. HTStream * me = HTFWriter_new(request, fp, NO);
  421. me->filename = filename;
  422. if ((me->end_command = (char  *) HT_MALLOC((strlen((char *) param) + 10 + 3*strlen(filename)))) == NULL)
  423.     HT_OUTOFMEM("SaveAndExecute");
  424.         sprintf (me->end_command, (char *)param, filename, filename, filename);
  425. return me;
  426.     }
  427.     HT_FREE(filename);
  428.     return HTErrorStream();
  429. }
  430. /* Save and Call Back
  431. ** ------------------
  432. ** This stream works exactly like the TSaveAndExecute
  433. ** stream but in addition when EOF has been reached, it checks whether a
  434. ** callback function has been associated with the request object in which
  435. ** case, this callback is being called. This can be use by the
  436. ** application to do some processing after the system command
  437. ** has terminated. The callback function is called with the file name of
  438. ** the temporary file as parameter.
  439. */
  440. PUBLIC HTStream* HTSaveAndCallback (HTRequest * request,
  441.     void * param,
  442.     HTFormat input_format,
  443.     HTFormat output_format,
  444.     HTStream * output_stream)
  445. {
  446.     HTStream * me = HTSaveAndExecute(request, param, input_format,
  447.      output_format, output_stream);
  448.     if (me) {
  449. me->callback = HTRequest_callback(request);
  450. return me;
  451.     }
  452.     return HTErrorStream();
  453. }