abyss_http.c

Go to the documentation of this file.
00001 /* Copyright information is at the end of the file */
00002 
00003 #include <ctype.h>
00004 #include <assert.h>
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <string.h>
00008 #include <errno.h>
00009 #include <time.h>
00010 
00011 #include <xmlrpc-c/config.h>
00012 #include "abyss_mallocvar.h"
00013 #include "abyss_xmlrpc_int.h"
00014 #include <xmlrpc-c/abyss.h>
00015 
00016 #include "abyss_server.h"
00017 #include "abyss_session.h"
00018 #include "abyss_conn.h"
00019 #include "abyss_token.h"
00020 #include "abyss_date.h"
00021 #include "abyss_data.h"
00022 #include "abyss_info.h"
00023 
00024 #include "abyss_http.h"
00025 
00026 /*********************************************************************
00027 ** Request Parser
00028 *********************************************************************/
00029 
00030 /*********************************************************************
00031 ** Request
00032 *********************************************************************/
00033 
00034 static void
00035 initRequestInfo(TRequestInfo * const requestInfoP,
00036                 httpVersion    const httpVersion,
00037                 const char *   const requestLine,
00038                 TMethod        const httpMethod,
00039                 const char *   const host,
00040                 unsigned int   const port,
00041                 const char *   const path,
00042                 const char *   const query) {
00043 /*----------------------------------------------------------------------------
00044   Set up the request info structure.  For information that is
00045   controlled by headers, use the defaults -- I.e. the value that
00046   applies if the request contains no applicable header.
00047 -----------------------------------------------------------------------------*/
00048     requestInfoP->requestline = requestLine;
00049     requestInfoP->method      = httpMethod;
00050     requestInfoP->host        = host;
00051     requestInfoP->port        = port;
00052     requestInfoP->uri         = path;
00053     requestInfoP->query       = query;
00054     requestInfoP->from        = NULL;
00055     requestInfoP->useragent   = NULL;
00056     requestInfoP->referer     = NULL;
00057     requestInfoP->user        = NULL;
00058 
00059     if (httpVersion.major > 1 ||
00060         (httpVersion.major == 1 && httpVersion.minor >= 1))
00061         requestInfoP->keepalive = TRUE;
00062     else
00063         requestInfoP->keepalive = FALSE;
00064 }
00065 
00066 
00067 
00068 static void
00069 freeRequestInfo(TRequestInfo * const requestInfoP) {
00070 
00071     if (requestInfoP->requestline)
00072         xmlrpc_strfree(requestInfoP->requestline);
00073 
00074     if (requestInfoP->user)
00075         xmlrpc_strfree(requestInfoP->user);
00076 }
00077 
00078 
00079 
00080 void
00081 RequestInit(TSession * const sessionP,
00082             TConn *    const connectionP) {
00083 
00084     time_t nowtime;
00085 
00086     sessionP->validRequest = false;  /* Don't have valid request yet */
00087 
00088     time(&nowtime);
00089     sessionP->date = *gmtime(&nowtime);
00090 
00091     sessionP->conn = connectionP;
00092 
00093     sessionP->responseStarted = FALSE;
00094 
00095     sessionP->chunkedwrite = FALSE;
00096     sessionP->chunkedwritemode = FALSE;
00097 
00098     ListInit(&sessionP->cookies);
00099     ListInit(&sessionP->ranges);
00100     TableInit(&sessionP->request_headers);
00101     TableInit(&sessionP->response_headers);
00102 
00103     sessionP->status = 0;  /* No status from handler yet */
00104 
00105     StringAlloc(&(sessionP->header));
00106 }
00107 
00108 
00109 
00110 void
00111 RequestFree(TSession * const sessionP) {
00112 
00113     if (sessionP->validRequest)
00114         freeRequestInfo(&sessionP->request_info);
00115 
00116     ListFree(&sessionP->cookies);
00117     ListFree(&sessionP->ranges);
00118     TableFree(&sessionP->request_headers);
00119     TableFree(&sessionP->response_headers);
00120     StringFree(&(sessionP->header));
00121 }
00122 
00123 
00124 
00125 static void
00126 readRequestLine(TSession *   const sessionP,
00127                 char **      const requestLineP,
00128                 uint16_t *   const httpErrorCodeP) {
00129 
00130     *httpErrorCodeP = 0;
00131 
00132     /* Ignore CRLFs in the beginning of the request (RFC2068-P30) */
00133     do {
00134         abyss_bool success;
00135         success = ConnReadHeader(sessionP->conn, requestLineP);
00136         if (!success)
00137             *httpErrorCodeP = 408;  /* Request Timeout */
00138     } while (!*httpErrorCodeP && (*requestLineP)[0] == '\0');
00139 }
00140 
00141 
00142 
00143 static void
00144 unescapeUri(char *       const uri,
00145             abyss_bool * const errorP) {
00146 
00147     char * x;
00148     char * y;
00149 
00150     x = y = uri;
00151     
00152     *errorP = FALSE;
00153 
00154     while (*x && !*errorP) {
00155         switch (*x) {
00156         case '%': {
00157             char c;
00158             ++x;
00159             c = tolower(*x++);
00160             if ((c >= '0') && (c <= '9'))
00161                 c -= '0';
00162             else if ((c >= 'a') && (c <= 'f'))
00163                 c -= 'a' - 10;
00164             else
00165                 *errorP = TRUE;
00166 
00167             if (!*errorP) {
00168                 char d;
00169                 d = tolower(*x++);
00170                 if ((d >= '0') && (d <= '9'))
00171                     d -= '0';
00172                 else if ((d >= 'a') && (d <= 'f'))
00173                     d -= 'a' - 10;
00174                 else
00175                     *errorP = TRUE;
00176 
00177                 if (!*errorP)
00178                     *y++ = ((c << 4) | d);
00179             }
00180         } break;
00181 
00182         default:
00183             *y++ = *x++;
00184             break;
00185         }
00186     }
00187     *y = '\0';
00188 }
00189 
00190 
00191 
00192 static void
00193 parseHostPort(char *           const hostport,
00194               const char **    const hostP,
00195               unsigned short * const portP,
00196               uint16_t *       const httpErrorCodeP) {
00197     
00198     char * colonPos;
00199 
00200     colonPos = strchr(hostport, ':');
00201     if (colonPos) {
00202         const char * p;
00203         uint32_t port;
00204 
00205         *colonPos = '\0';  /* Split hostport at the colon */
00206 
00207         *hostP = hostport;
00208 
00209         for (p = colonPos + 1, port = 0;
00210              isdigit(*p) && port < 65535;
00211              (port = port * 10 + (*p - '0')), ++p);
00212             
00213         *portP = port;
00214 
00215         if (*p || port == 0)
00216             *httpErrorCodeP = 400;  /* Bad Request */
00217         else
00218             *httpErrorCodeP = 0;
00219     } else {
00220         *hostP          = hostport;
00221         *portP          = 80;
00222         *httpErrorCodeP = 0;
00223     }
00224 }
00225 
00226 
00227 
00228 static void
00229 parseRequestUri(char *           const requestUri,
00230                 const char **    const hostP,
00231                 const char **    const pathP,
00232                 const char **    const queryP,
00233                 unsigned short * const portP,
00234                 uint16_t *       const httpErrorCodeP) {
00235 /*----------------------------------------------------------------------------
00236   Parse the request URI (in the request line
00237   "GET http://www.myserver.com/myfile?parm HTTP/1.1",
00238   "http://www.myserver.com/myfile?parm" is the request URI).
00239 
00240   This destroys *requestUri and returns pointers into *requestUri!
00241 
00242   This is extremely ugly.  We need to redo it with dynamically allocated
00243   storage.  We should return individual malloc'ed strings.
00244 -----------------------------------------------------------------------------*/
00245     abyss_bool error;
00246 
00247     unescapeUri(requestUri, &error);
00248     
00249     if (error)
00250         *httpErrorCodeP = 400;  /* Bad Request */
00251     else {
00252         char * requestUriNoQuery;
00253            /* The request URI with any query (the stuff marked by a question
00254               mark at the end of a request URI) chopped off.
00255            */
00256         {
00257             /* Split requestUri at the question mark */
00258             char * const qmark = strchr(requestUri, '?');
00259             
00260             if (qmark) {
00261                 *qmark = '\0';
00262                 *queryP = qmark + 1;
00263             } else
00264                 *queryP = NULL;
00265         }
00266         
00267         requestUriNoQuery = requestUri;
00268 
00269         if (requestUriNoQuery[0] == '/') {
00270             *hostP = NULL;
00271             *pathP = requestUriNoQuery;
00272             *portP = 80;
00273         } else {
00274             if (!xmlrpc_strneq(requestUriNoQuery, "http://", 7))
00275                 *httpErrorCodeP = 400;  /* Bad Request */
00276             else {
00277                 char * const hostportpath = &requestUriNoQuery[7];
00278                 char * const slashPos = strchr(hostportpath, '/');
00279                 char * hostport;
00280                 
00281                 if (slashPos) {
00282                     char * p;
00283                     *pathP = slashPos;
00284                     
00285                     /* Nul-terminate the host name.  To make space for
00286                        it, slide the whole name back one character.
00287                        This moves it into the space now occupied by
00288                        the end of "http://", which we don't need.
00289                     */
00290                     for (p = hostportpath; *p != '/'; ++p)
00291                         *(p-1) = *p;
00292                     *(p-1) = '\0';
00293                     
00294                     hostport = hostportpath - 1;
00295                     *httpErrorCodeP = 0;
00296                 } else {
00297                     *pathP = "*";
00298                     hostport = hostportpath;
00299                     *httpErrorCodeP = 0;
00300                 }
00301                 if (!*httpErrorCodeP)
00302                     parseHostPort(hostport, hostP, portP, httpErrorCodeP);
00303             }
00304         }
00305     }
00306 }
00307 
00308 
00309 
00310 static void
00311 parseRequestLine(char *           const requestLine,
00312                  TMethod *        const httpMethodP,
00313                  httpVersion *    const httpVersionP,
00314                  const char **    const hostP,
00315                  unsigned short * const portP,
00316                  const char **    const pathP,
00317                  const char **    const queryP,
00318                  abyss_bool *     const moreLinesP,
00319                  uint16_t *       const httpErrorCodeP) {
00320 /*----------------------------------------------------------------------------
00321    Modifies *header1 and returns pointers to its storage!
00322 -----------------------------------------------------------------------------*/
00323     const char * httpMethodName;
00324     char * p;
00325 
00326     p = requestLine;
00327 
00328     /* Jump over spaces */
00329     NextToken((const char **)&p);
00330 
00331     httpMethodName = GetToken(&p);
00332     if (!httpMethodName)
00333         *httpErrorCodeP = 400;  /* Bad Request */
00334     else {
00335         char * requestUri;
00336 
00337         if (xmlrpc_streq(httpMethodName, "GET"))
00338             *httpMethodP = m_get;
00339         else if (xmlrpc_streq(httpMethodName, "PUT"))
00340             *httpMethodP = m_put;
00341         else if (xmlrpc_streq(httpMethodName, "OPTIONS"))
00342             *httpMethodP = m_options;
00343         else if (xmlrpc_streq(httpMethodName, "DELETE"))
00344             *httpMethodP = m_delete;
00345         else if (xmlrpc_streq(httpMethodName, "POST"))
00346             *httpMethodP = m_post;
00347         else if (xmlrpc_streq(httpMethodName, "TRACE"))
00348             *httpMethodP = m_trace;
00349         else if (xmlrpc_streq(httpMethodName, "HEAD"))
00350             *httpMethodP = m_head;
00351         else
00352             *httpMethodP = m_unknown;
00353         
00354         /* URI and Query Decoding */
00355         NextToken((const char **)&p);
00356 
00357         
00358         requestUri = GetToken(&p);
00359         if (!requestUri)
00360             *httpErrorCodeP = 400;  /* Bad Request */
00361         else {
00362             parseRequestUri(requestUri, hostP, pathP, queryP, portP,
00363                             httpErrorCodeP);
00364 
00365             if (!*httpErrorCodeP) {
00366                 const char * httpVersion;
00367 
00368                 NextToken((const char **)&p);
00369         
00370                 /* HTTP Version Decoding */
00371                 
00372                 httpVersion = GetToken(&p);
00373                 if (httpVersion) {
00374                     uint32_t vmin, vmaj;
00375                     if (sscanf(httpVersion, "HTTP/%d.%d", &vmaj, &vmin) != 2)
00376                         *httpErrorCodeP = 400;  /* Bad Request */
00377                     else {
00378                         httpVersionP->major = vmaj;
00379                         httpVersionP->minor = vmin;
00380                         *httpErrorCodeP = 0;  /* no error */
00381                     }
00382                     *moreLinesP = TRUE;
00383                 } else {
00384                     /* There is no HTTP version, so this is a single
00385                        line request.
00386                     */
00387                     *httpErrorCodeP = 0;  /* no error */
00388                     *moreLinesP = FALSE;
00389                 }
00390             }
00391         }
00392     }
00393 }
00394 
00395 
00396 
00397 static void
00398 strtolower(char * const s) {
00399 
00400     char * t;
00401 
00402     t = &s[0];
00403     while (*t) {
00404         *t = tolower(*t);
00405         ++t;
00406     }
00407 }
00408 
00409 
00410 
00411 static void
00412 getFieldNameToken(char **    const pP,
00413                   char **    const fieldNameP,
00414                   uint16_t * const httpErrorCodeP) {
00415     
00416     char * fieldName;
00417 
00418     NextToken((const char **)pP);
00419     
00420     fieldName = GetToken(pP);
00421     if (!fieldName)
00422         *httpErrorCodeP = 400;  /* Bad Request */
00423     else {
00424         if (fieldName[strlen(fieldName)-1] != ':')
00425             /* Not a valid field name */
00426             *httpErrorCodeP = 400;  /* Bad Request */
00427         else {
00428             fieldName[strlen(fieldName)-1] = '\0';  /* remove trailing colon */
00429 
00430             strtolower(fieldName);
00431             
00432             *httpErrorCodeP = 0;  /* no error */
00433             *fieldNameP = fieldName;
00434         }
00435     }
00436 }
00437 
00438 
00439 
00440 static void
00441 processHeader(const char * const fieldName,
00442               char *       const fieldValue,
00443               TSession *   const sessionP,
00444               uint16_t *   const httpErrorCodeP) {
00445 /*----------------------------------------------------------------------------
00446    We may modify *fieldValue, and we put pointers to *fieldValue and
00447    *fieldName into *sessionP.
00448 
00449    We must fix this some day.  *sessionP should point to individual
00450    malloc'ed strings.
00451 -----------------------------------------------------------------------------*/
00452     *httpErrorCodeP = 0;  /* initial assumption */
00453 
00454     if (xmlrpc_streq(fieldName, "connection")) {
00455         if (xmlrpc_strcaseeq(fieldValue, "keep-alive"))
00456             sessionP->request_info.keepalive = TRUE;
00457         else
00458             sessionP->request_info.keepalive = FALSE;
00459     } else if (xmlrpc_streq(fieldName, "host"))
00460         parseHostPort(fieldValue, &sessionP->request_info.host,
00461                       &sessionP->request_info.port, httpErrorCodeP);
00462     else if (xmlrpc_streq(fieldName, "from"))
00463         sessionP->request_info.from = fieldValue;
00464     else if (xmlrpc_streq(fieldName, "user-agent"))
00465         sessionP->request_info.useragent = fieldValue;
00466     else if (xmlrpc_streq(fieldName, "referer"))
00467         sessionP->request_info.referer = fieldValue;
00468     else if (xmlrpc_streq(fieldName, "range")) {
00469         if (xmlrpc_strneq(fieldValue, "bytes=", 6)) {
00470             abyss_bool succeeded;
00471             succeeded = ListAddFromString(&sessionP->ranges, &fieldValue[6]);
00472             *httpErrorCodeP = succeeded ? 0 : 400;
00473         }
00474     } else if (xmlrpc_streq(fieldName, "cookies")) {
00475         abyss_bool succeeded;
00476         succeeded = ListAddFromString(&sessionP->cookies, fieldValue);
00477         *httpErrorCodeP = succeeded ? 0 : 400;
00478     }
00479 }
00480 
00481 
00482 
00483 abyss_bool
00484 RequestRead(TSession * const sessionP) {
00485     uint16_t httpErrorCode;  /* zero for no error */
00486     char * requestLine;
00487 
00488     readRequestLine(sessionP, &requestLine, &httpErrorCode);
00489     if (!httpErrorCode) {
00490         TMethod httpMethod;
00491         const char * host;
00492         const char * path;
00493         const char * query;
00494         unsigned short port;
00495         abyss_bool moreHeaders=false;
00496 
00497         parseRequestLine(requestLine, &httpMethod, &sessionP->version,
00498                          &host, &port, &path, &query,
00499                          &moreHeaders, &httpErrorCode);
00500 
00501         if (!httpErrorCode)
00502             initRequestInfo(&sessionP->request_info, sessionP->version,
00503                             strdup(requestLine),
00504                             httpMethod, host, port, path, query);
00505 
00506         while (moreHeaders && !httpErrorCode) {
00507             char * p;
00508             abyss_bool succeeded;
00509             succeeded = ConnReadHeader(sessionP->conn, &p);
00510             if (!succeeded)
00511                 httpErrorCode = 408;  /* Request Timeout */
00512             else {
00513                 if (!*p)
00514                     /* We have reached the empty line so all the request
00515                        was read.
00516                     */
00517                     moreHeaders = FALSE;
00518                 else {
00519                     char * fieldName;
00520                     getFieldNameToken(&p, &fieldName, &httpErrorCode);
00521                     if (!httpErrorCode) {
00522                         char * fieldValue;
00523 
00524                         NextToken((const char **)&p);
00525                         
00526                         fieldValue = p;
00527                         
00528                         TableAdd(&sessionP->request_headers,
00529                                  fieldName, fieldValue);
00530                         
00531                         processHeader(fieldName, fieldValue, sessionP,
00532                                       &httpErrorCode);
00533                     }
00534                 }
00535             }
00536         }
00537     }
00538     if (httpErrorCode)
00539         ResponseStatus(sessionP, httpErrorCode);
00540     else
00541         sessionP->validRequest = true;
00542 
00543     return !httpErrorCode;
00544 }
00545 
00546 
00547 
00548 char *RequestHeaderValue(TSession *r,char *name)
00549 {
00550     return (TableFind(&r->request_headers,name));
00551 }
00552 
00553 
00554 
00555 abyss_bool
00556 RequestValidURI(TSession * const sessionP) {
00557 
00558     if (!sessionP->request_info.uri)
00559         return FALSE;
00560     
00561     if (xmlrpc_streq(sessionP->request_info.uri, "*"))
00562         return (sessionP->request_info.method != m_options);
00563 
00564     if (strchr(sessionP->request_info.uri, '*'))
00565         return FALSE;
00566 
00567     return TRUE;
00568 }
00569 
00570 
00571 
00572 abyss_bool
00573 RequestValidURIPath(TSession * const sessionP) {
00574 
00575     uint32_t i;
00576     const char * p;
00577 
00578     p = sessionP->request_info.uri;
00579 
00580     i = 0;
00581 
00582     if (*p == '/') {
00583         i = 1;
00584         while (*p)
00585             if (*(p++) == '/') {
00586                 if (*p == '/')
00587                     break;
00588                 else if ((strncmp(p,"./",2) == 0) || (strcmp(p, ".") == 0))
00589                     ++p;
00590                 else if ((strncmp(p, "../", 2) == 0) ||
00591                          (strcmp(p, "..") == 0)) {
00592                     p += 2;
00593                     --i;
00594                     if (i == 0)
00595                         break;
00596                 }
00597                 /* Prevent accessing hidden files (starting with .) */
00598                 else if (*p == '.')
00599                     return FALSE;
00600                 else
00601                     if (*p)
00602                         ++i;
00603             }
00604     }
00605     return (*p == 0 && i > 0);
00606 }
00607 
00608 
00609 
00610 abyss_bool
00611 RequestAuth(TSession *r,char *credential,char *user,char *pass) {
00612 
00613     char *p,*x;
00614     char z[80],t[80];
00615 
00616     p=RequestHeaderValue(r,"authorization");
00617     if (p) {
00618         NextToken((const char **)&p);
00619         x=GetToken(&p);
00620         if (x) {
00621             if (strcasecmp(x,"basic")==0) {
00622                 NextToken((const char **)&p);
00623                 sprintf(z,"%s:%s",user,pass);
00624                 Base64Encode(z,t);
00625 
00626                 if (strcmp(p,t)==0) {
00627                     r->request_info.user=strdup(user);
00628                     return TRUE;
00629                 };
00630             };
00631         }
00632     };
00633 
00634     sprintf(z,"Basic realm=\"%s\"",credential);
00635     ResponseAddField(r,"WWW-Authenticate",z);
00636     ResponseStatus(r,401);
00637     return FALSE;
00638 }
00639 
00640 
00641 
00642 /*********************************************************************
00643 ** Range
00644 *********************************************************************/
00645 
00646 abyss_bool RangeDecode(char *str,uint64_t filesize,uint64_t *start,uint64_t *end)
00647 {
00648     char *ss;
00649 
00650     *start=0;
00651     *end=filesize-1;
00652 
00653     if (*str=='-')
00654     {
00655         *start=filesize-strtol(str+1,&ss,10);
00656         return ((ss!=str) && (!*ss));
00657     };
00658 
00659     *start=strtol(str,&ss,10);
00660 
00661     if ((ss==str) || (*ss!='-'))
00662         return FALSE;
00663 
00664     str=ss+1;
00665 
00666     if (!*str)
00667         return TRUE;
00668 
00669     *end=strtol(str,&ss,10);
00670 
00671     if ((ss==str) || (*ss) || (*end<*start))
00672         return FALSE;
00673 
00674     return TRUE;
00675 }
00676 
00677 /*********************************************************************
00678 ** HTTP
00679 *********************************************************************/
00680 
00681 const char *
00682 HTTPReasonByStatus(uint16_t const code) {
00683 
00684     struct _HTTPReasons {
00685         uint16_t status;
00686         const char * reason;
00687     };
00688 
00689     static struct _HTTPReasons const reasons[] =  {
00690         { 100,"Continue" }, 
00691         { 101,"Switching Protocols" }, 
00692         { 200,"OK" }, 
00693         { 201,"Created" }, 
00694         { 202,"Accepted" }, 
00695         { 203,"Non-Authoritative Information" }, 
00696         { 204,"No Content" }, 
00697         { 205,"Reset Content" }, 
00698         { 206,"Partial Content" }, 
00699         { 300,"Multiple Choices" }, 
00700         { 301,"Moved Permanently" }, 
00701         { 302,"Moved Temporarily" }, 
00702         { 303,"See Other" }, 
00703         { 304,"Not Modified" }, 
00704         { 305,"Use Proxy" }, 
00705         { 400,"Bad Request" }, 
00706         { 401,"Unauthorized" }, 
00707         { 402,"Payment Required" }, 
00708         { 403,"Forbidden" }, 
00709         { 404,"Not Found" }, 
00710         { 405,"Method Not Allowed" }, 
00711         { 406,"Not Acceptable" }, 
00712         { 407,"Proxy Authentication Required" }, 
00713         { 408,"Request Timeout" }, 
00714         { 409,"Conflict" }, 
00715         { 410,"Gone" }, 
00716         { 411,"Length Required" }, 
00717         { 412,"Precondition Failed" }, 
00718         { 413,"Request Entity Too Large" }, 
00719         { 414,"Request-URI Too Long" }, 
00720         { 415,"Unsupported Media Type" }, 
00721         { 500,"Internal Server Error" }, 
00722         { 501,"Not Implemented" }, 
00723         { 502,"Bad Gateway" }, 
00724         { 503,"Service Unavailable" }, 
00725         { 504,"Gateway Timeout" }, 
00726         { 505,"HTTP Version Not Supported" },
00727         { 000, NULL }
00728     };
00729     const struct _HTTPReasons * reasonP;
00730 
00731     reasonP = &reasons[0];
00732 
00733     while (reasonP->status <= code)
00734         if (reasonP->status == code)
00735             return reasonP->reason;
00736         else
00737             ++reasonP;
00738 
00739     return "No Reason";
00740 }
00741 
00742 
00743 
00744 int32_t
00745 HTTPRead(TSession *   const s ATTR_UNUSED,
00746          const char * const buffer ATTR_UNUSED,
00747          uint32_t     const len ATTR_UNUSED) {
00748 
00749     return 0;
00750 }
00751 
00752 
00753 
00754 abyss_bool
00755 HTTPWriteBodyChunk(TSession *   const sessionP,
00756                    const char * const buffer,
00757                    uint32_t     const len) {
00758 
00759     abyss_bool succeeded;
00760 
00761     if (sessionP->chunkedwrite && sessionP->chunkedwritemode) {
00762         char chunkHeader[16];
00763 
00764         sprintf(chunkHeader, "%x\r\n", len);
00765 
00766         succeeded =
00767             ConnWrite(sessionP->conn, chunkHeader, strlen(chunkHeader));
00768         if (succeeded) {
00769             succeeded = ConnWrite(sessionP->conn, buffer, len);
00770             if (succeeded)
00771                 succeeded = ConnWrite(sessionP->conn, "\r\n", 2);
00772         }
00773     } else
00774         succeeded = ConnWrite(sessionP->conn, buffer, len);
00775 
00776     return succeeded;
00777 }
00778 
00779 
00780 
00781 abyss_bool
00782 HTTPWriteEndChunk(TSession * const sessionP) {
00783 
00784     abyss_bool retval;
00785 
00786     if (sessionP->chunkedwritemode && sessionP->chunkedwrite) {
00787         /* May be one day trailer dumping will be added */
00788         sessionP->chunkedwritemode = FALSE;
00789         retval = ConnWrite(sessionP->conn, "0\r\n\r\n", 5);
00790     } else
00791         retval = TRUE;
00792 
00793     return retval;
00794 }
00795 
00796 
00797 
00798 abyss_bool
00799 HTTPKeepalive(TSession * const sessionP) {
00800 /*----------------------------------------------------------------------------
00801    Return value: the connection should be kept alive after the session
00802    *sessionP is over.
00803 -----------------------------------------------------------------------------*/
00804     return (sessionP->request_info.keepalive &&
00805             !sessionP->serverDeniesKeepalive &&
00806             sessionP->status < 400);
00807 }
00808 
00809 
00810 
00811 /******************************************************************************
00812 **
00813 ** http.c
00814 **
00815 ** Copyright (C) 2000 by Moez Mahfoudh <mmoez@bigfoot.com>.
00816 ** All rights reserved.
00817 **
00818 ** Redistribution and use in source and binary forms, with or without
00819 ** modification, are permitted provided that the following conditions
00820 ** are met:
00821 ** 1. Redistributions of source code must retain the above copyright
00822 **    notice, this list of conditions and the following disclaimer.
00823 ** 2. Redistributions in binary form must reproduce the above copyright
00824 **    notice, this list of conditions and the following disclaimer in the
00825 **    documentation and/or other materials provided with the distribution.
00826 ** 3. The name of the author may not be used to endorse or promote products
00827 **    derived from this software without specific prior written permission.
00828 ** 
00829 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00830 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00831 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00832 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00833 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00834 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00835 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00836 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00837 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00838 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00839 ** SUCH DAMAGE.
00840 **
00841 ******************************************************************************/

Generated on Thu May 17 10:00:23 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6