Annotation of libwww/Library/src/HTMIMERq.c, revision 2.27

2.1       frystyk     1: /*                                                                  HTMIMERq.c
2.10      frystyk     2: **     MIME ENTITY HEADERS GENERATION
2.1       frystyk     3: **
2.15      frystyk     4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.27    ! frystyk     6: **     @(#) $Id: HTMIMERq.c,v 2.26 1996/08/19 18:30:45 frystyk Exp $
2.15      frystyk     7: **
2.1       frystyk     8: **     This module implements the output stream for MIME used for sending
2.10      frystyk     9: **     requests with a entity body to HTTP, NEWS, etc. or for generating
                     10: **     responses
2.1       frystyk    11: **
                     12: ** History:
                     13: **     Jan 95 HFN      Written
                     14: */
                     15: 
                     16: /* Library Includes */
2.14      frystyk    17: #include "sysdep.h"
2.21      frystyk    18: #include "WWWUtil.h"
                     19: #include "WWWCore.h"
2.7       frystyk    20: #include "HTAncMan.h"
2.1       frystyk    21: #include "HTNetMan.h"
2.21      frystyk    22: #include "HTReqMan.h"
2.2       frystyk    23: #include "HTHeader.h"
2.21      frystyk    24: #include "HTMIMERq.h"                                         /* Implements */
2.1       frystyk    25: 
2.17      frystyk    26: #define PUTC(c)                (*me->target->isa->put_character)(me->target, c)
                     27: #define PUTS(s)                (*me->target->isa->put_string)(me->target, s)
2.1       frystyk    28: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     29: 
                     30: struct _HTStream {
2.14      frystyk    31:     const HTStreamClass *      isa;
2.1       frystyk    32:     HTStream *                 target;
                     33:     HTRequest *                        request;
2.23      frystyk    34:     BOOL                       put_fix;
2.10      frystyk    35:     BOOL                       endHeader;
2.1       frystyk    36:     BOOL                       transparent;
                     37: };
                     38: 
2.27    ! frystyk    39: #define HT_MAX_WAIT            8      /* Max number of secs to wait for PUT */
2.25      frystyk    40: 
2.1       frystyk    41: /* ------------------------------------------------------------------------- */
                     42: /*                         MIME Output Request Stream                       */
                     43: /* ------------------------------------------------------------------------- */
                     44: 
                     45: /*     MIMEMakeRequest
                     46: **     ---------------
2.10      frystyk    47: **     Generates the BODY parts of a MIME message.
2.1       frystyk    48: */
2.2       frystyk    49: PRIVATE int MIMEMakeRequest (HTStream * me, HTRequest * request)
2.1       frystyk    50: {
2.17      frystyk    51:     char crlf[3];
2.10      frystyk    52:     char linebuf[256];                 /* @@@ */
2.21      frystyk    53:     HTParentAnchor * entity = HTRequest_entityAnchor(request);
                     54:     HTEnHd EntityMask = HTRequest_enHd(request);
2.17      frystyk    55:     *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1       frystyk    56: 
2.21      frystyk    57:     if (EntityMask & HT_E_ALLOW) {
2.10      frystyk    58:        /* @@@@@@@@@@ */
                     59:     }
2.21      frystyk    60:     if (EntityMask & HT_E_CONTENT_ENCODING && entity->content_encoding){
2.17      frystyk    61:        BOOL first = YES;
                     62:        HTList * cur = entity->content_encoding;
                     63:        HTEncoding pres;
                     64:        while ((pres = (HTEncoding) HTList_nextObject(cur))) {
                     65:            if (first) {
                     66:                PUTS("Content-Encoding: ");
                     67:                first = NO;
                     68:            } else
                     69:                PUTC(',');
                     70:            PUTS(HTAtom_name(pres));
                     71:        }
                     72:        if (!first) PUTBLOCK(crlf, 2);
2.1       frystyk    73:     }
2.10      frystyk    74:     
2.21      frystyk    75:     if (EntityMask & HT_E_CONTENT_LANGUAGE && entity->content_language){
2.17      frystyk    76:        BOOL first = YES;
                     77:        HTList * cur = entity->content_language;
                     78:        HTLanguage pres;
                     79:        while ((pres = (HTLanguage) HTList_nextObject(cur))) {
                     80:            if (first) {
                     81:                PUTS("Content-Language: ");
                     82:                first = NO;
                     83:            } else
                     84:                PUTC(',');
                     85:            PUTS(HTAtom_name(pres));
                     86:        }
                     87:        if (!first) PUTBLOCK(crlf, 2);
2.1       frystyk    88:     }
2.21      frystyk    89:     if (EntityMask & HT_E_CONTENT_LENGTH) {
2.20      frystyk    90:        if (entity->content_length >= 0) {
                     91:            sprintf(linebuf, "Content-Length: %ld%c%c",
                     92:                    entity->content_length, CR, LF);
                     93:            PUTBLOCK(linebuf, (int) strlen(linebuf));   
                     94:        } else {
                     95:            HTEncoding chunked = HTAtom_for("chunked");
                     96:            HTAnchor_setTransfer(entity, chunked);
                     97:        }
2.10      frystyk    98:     }
2.21      frystyk    99:     if (EntityMask & HT_E_CTE && entity->transfer) {
2.20      frystyk   100:        HTEncoding transfer = HTAnchor_transfer(entity);
                    101:        if (!HTFormat_isUnityTransfer(transfer)) {
                    102:            sprintf(linebuf, "Transfer-Encoding: %s%c%c",
                    103:                    HTAtom_name(transfer), CR, LF);
                    104:            PUTBLOCK(linebuf, (int) strlen(linebuf));
                    105:        }
2.1       frystyk   106:     }
2.21      frystyk   107:     if (EntityMask & HT_E_CONTENT_TYPE && entity->content_type &&
2.19      frystyk   108:        entity->content_type != WWW_UNKNOWN) {
                    109:        HTAssocList * parameters = HTAnchor_formatParam(entity);
                    110: 
                    111:        /* Output the content type */
                    112:        PUTS("Content-Type: ");
                    113:        PUTS(HTAtom_name(entity->content_type));
                    114: 
                    115:        /* Add all parameters */
                    116:        if (parameters) {
                    117:            HTAssoc * pres;
                    118:            while ((pres = (HTAssoc *) HTAssocList_nextObject(parameters))) {
                    119:                PUTS(";");
                    120:                PUTS(HTAssoc_name(pres));
                    121:                PUTS("=");
                    122:                PUTS(HTAssoc_value(pres));
                    123:            }
                    124:        }
                    125:        PUTBLOCK(crlf, 2);
                    126: #if 0
2.10      frystyk   127:        if (entity->charset) {
                    128:            strcat(linebuf, "; charset=");
                    129:            strcat(linebuf, HTAtom_name(entity->charset));
                    130:        }
                    131:        if (entity->level) {
                    132:            strcat(linebuf, "; level=");
                    133:            strcat(linebuf, HTAtom_name(entity->level));
                    134:        }
                    135:        len = strlen(linebuf);
                    136:        *(linebuf+len) = CR;
                    137:        *(linebuf+len+1) = LF;
                    138:        *(linebuf+len+2) = '\0';
                    139:        PUTBLOCK(linebuf, (int) len+2);
2.19      frystyk   140: #endif
2.10      frystyk   141:     }
2.21      frystyk   142:     if (EntityMask & HT_E_DERIVED_FROM && entity->derived_from) {
2.10      frystyk   143:        sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
                    144:                CR, LF);
2.2       frystyk   145:        PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1       frystyk   146:     }
2.21      frystyk   147:     if (EntityMask & HT_E_EXPIRES) {
2.10      frystyk   148:        if (entity->expires != -1) {
                    149:            sprintf(linebuf, "Expires: %s%c%c",
                    150:                    HTDateTimeStr(&entity->expires, NO), CR,LF);
2.2       frystyk   151:            PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1       frystyk   152:        }
2.10      frystyk   153:     }
2.21      frystyk   154:     if (EntityMask & HT_E_LAST_MODIFIED) {
2.10      frystyk   155:        if (entity->last_modified != -1) {
                    156:            sprintf(linebuf, "Last-Modified: %s%c%c",
                    157:                    HTDateTimeStr(&entity->last_modified, NO), CR,LF);
2.2       frystyk   158:            PUTBLOCK(linebuf, (int) strlen(linebuf));
2.1       frystyk   159:        }
2.10      frystyk   160:     }
2.21      frystyk   161:     if (EntityMask & HT_E_LINK) {              /* @@@@@@@@@@ */
2.1       frystyk   162: 
2.10      frystyk   163:     }
2.21      frystyk   164:     if (EntityMask & HT_E_TITLE) {             /* @@@@@@@@@@ */
2.1       frystyk   165: 
2.10      frystyk   166:     }
2.21      frystyk   167:     if (EntityMask & HT_E_URI) {               /* @@@@@@@@@@ */
2.1       frystyk   168: 
                    169:     }
2.21      frystyk   170:     if (EntityMask & HT_E_VERSION && entity->version) {
2.10      frystyk   171:        sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
                    172:        PUTBLOCK(linebuf, (int) strlen(linebuf));
                    173:     }
                    174:     if (me->endHeader) {
                    175:        sprintf(linebuf, "%c%c", CR, LF);          /* Blank line means "end" */
                    176:        PUTBLOCK(linebuf, (int) strlen(linebuf));
2.2       frystyk   177:     }
2.20      frystyk   178: 
                    179:     /*
                    180:     ** Now make sure that the body has the right format
                    181:     */
                    182: 
                    183:     /* Handle any Transfer encoding */
                    184:     {
                    185:        HTEncoding transfer = HTAnchor_transfer(entity);
                    186:        if (!HTFormat_isUnityTransfer(transfer)) {
                    187:            if (STREAM_TRACE) HTTrace("Building.... C-T-E stack\n");
                    188:            me->target = HTTransferCodingStack(transfer, me->target,
                    189:                                               request, NULL, YES);
                    190:        }
                    191:     }
                    192: 
                    193:     /* Handle any Content Encoding */
                    194:     {
                    195:        HTList * cc = HTAnchor_encoding(entity);
                    196:        if (cc) {
                    197:            if (STREAM_TRACE) HTTrace("Building.... C-E stack\n");
                    198:            me->target = HTContentDecodingStack(cc, me->target, request, NULL);
                    199:        }
                    200:     }
                    201: 
2.13      eric      202:     if (PROT_TRACE) HTTrace("MIME........ Generating Entity Headers\n");
2.2       frystyk   203:     return HT_OK;
2.1       frystyk   204: }
                    205: 
2.14      frystyk   206: PRIVATE int MIMERequest_put_block (HTStream * me, const char * b, int l)
2.1       frystyk   207: {
2.23      frystyk   208:     HTNet * net = HTRequest_net(me->request);
                    209:     if (me->transparent) {
                    210:        if (me->put_fix) {
                    211:            HTNet * net = HTRequest_net(me->request);
                    212:            HTEvent_unregister(net->sockfd, FD_READ);
                    213:            me->put_fix = NO;
                    214:        }
                    215:     } else {
2.1       frystyk   216:        MIMEMakeRequest(me, me->request);
2.9       frystyk   217:        if (HTRequest_isDestination(me->request)) {
2.21      frystyk   218:            HTNet * net = HTRequest_net(me->request);
2.9       frystyk   219:            (*me->target->isa->flush)(me->target);
2.21      frystyk   220:            HTNet_setBytesWritten(net, 0);
2.1       frystyk   221:        }
2.9       frystyk   222:        me->transparent = YES;  
2.22      frystyk   223: 
                    224:        /*
                    225:        **  If we know we are talking to an HTTP 1.1 server and we are sending
                    226:        **  an entity body then wait until we have received a 100 response
                    227:        */
                    228:        if (HTMethod_hasEntity(HTRequest_method(me->request))) {
                    229:            HTHost * host = HTNet_host(net);
                    230:            char * class = HTHost_class(host);
2.23      frystyk   231:            if (class && !strcmp(class, "http")) {
                    232: 
                    233:                /*
                    234:                ** If this is a HTTP/1.1 or later then wait for 100 code. If
                    235:                ** it is a HTTP/1.0 server then wait a bit and hope the best.
                    236:                */
                    237:                if (HTHost_version(host) >= 3) {
                    238:                    if (STREAM_TRACE)
                    239:                        HTTrace("MIME........ Waiting for 100...\n");
                    240:                    (*me->target->isa->flush)(me->target);
                    241:                    return HT_PAUSE;
                    242:                } else {
                    243:                    HTNet * net = HTRequest_net(me->request);
                    244:                    int zzzz = HTRequest_retrys(me->request);
                    245:                    zzzz = zzzz ? zzzz * 2 : 2;
2.25      frystyk   246:                    if (zzzz > HT_MAX_WAIT) zzzz = HT_MAX_WAIT;
2.23      frystyk   247:                    (*me->target->isa->flush)(me->target);
2.24      frystyk   248:                    if (STREAM_TRACE) HTTrace("MIME........ Sleeping for %d secs\n", zzzz);
2.23      frystyk   249:                    HTEvent_register(net->sockfd, me->request,
                    250:                                     (SockOps) FD_READ | FD_WRITE,
                    251:                                     net->cbf, net->priority);
                    252:                    SLEEP(zzzz);
                    253:                    me->put_fix = YES;
                    254:                    return HT_WOULD_BLOCK;
                    255:                }
2.22      frystyk   256:            }
                    257:        }
2.1       frystyk   258:     }
2.23      frystyk   259: 
                    260:     /* Check if we have written it all */
                    261:     if (b) {
                    262:        HTParentAnchor * entity = HTRequest_entityAnchor(me->request);
                    263:        long cl = HTAnchor_length(entity);
                    264:        return (cl>=0 && HTNet_bytesWritten(net) >= cl) ?
                    265:            HT_LOADED : PUTBLOCK(b, l);
                    266:     }
                    267:     return HT_OK;
2.1       frystyk   268: }
                    269: 
                    270: PRIVATE int MIMERequest_put_character (HTStream * me, char c)
                    271: {
                    272:     return MIMERequest_put_block(me, &c, 1);
                    273: }
                    274: 
2.14      frystyk   275: PRIVATE int MIMERequest_put_string (HTStream * me, const char * s)
2.1       frystyk   276: {
                    277:     return MIMERequest_put_block(me, s, strlen(s));
                    278: }
                    279: 
                    280: /*
                    281: **     Flushes header but doesn't free stream object
                    282: */
                    283: PRIVATE int MIMERequest_flush (HTStream * me)
                    284: {
                    285:     int status = MIMERequest_put_block(me, NULL, 0);
                    286:     return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
                    287: }
                    288: 
                    289: /*
                    290: **     Flushes data and frees stream object
                    291: */
                    292: PRIVATE int MIMERequest_free (HTStream * me)
                    293: {
                    294:     int status = MIMERequest_flush(me);
                    295:     if (status != HT_WOULD_BLOCK) {
                    296:        if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
                    297:            return HT_WOULD_BLOCK;
2.12      frystyk   298:        HT_FREE(me);
2.1       frystyk   299:     }
                    300:     return status;
                    301: }
                    302: 
2.4       frystyk   303: PRIVATE int MIMERequest_abort (HTStream * me, HTList * e)
2.1       frystyk   304: {
                    305:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.12      frystyk   306:     HT_FREE(me);
2.13      eric      307:     if (PROT_TRACE) HTTrace("MIMERequest. ABORTING...\n");
2.1       frystyk   308:     return HT_ERROR;
                    309: }
                    310: 
                    311: /*     MIMERequest Stream
                    312: **     -----------------
                    313: */
2.14      frystyk   314: PRIVATE const HTStreamClass MIMERequestClass =
2.1       frystyk   315: {              
                    316:     "MIMERequest",
                    317:     MIMERequest_flush,
                    318:     MIMERequest_free,
                    319:     MIMERequest_abort,
                    320:     MIMERequest_put_character,
                    321:     MIMERequest_put_string,
                    322:     MIMERequest_put_block
                    323: };
                    324: 
2.10      frystyk   325: PUBLIC HTStream * HTMIMERequest_new (HTRequest * request, HTStream * target,
                    326:                                     BOOL endHeader)
2.1       frystyk   327: {
2.12      frystyk   328:     HTStream * me;
                    329:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    330:         HT_OUTOFMEM("HTMIMERequest_new");
2.1       frystyk   331:     me->isa = &MIMERequestClass;
                    332:     me->target = target;
                    333:     me->request = request;
2.10      frystyk   334:     me->endHeader = endHeader;
2.1       frystyk   335:     me->transparent = NO;
                    336:     return me;
                    337: }

Webmaster