Annotation of libwww/Library/src/HTFWrite.c, revision 2.28

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

Webmaster