httpd.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00033 /*
00034  * $Log: httpd.c,v $
00035  * Revision 1.15  2006/11/08 08:52:31  haraldkipp
00036  * Bugfix, kindly provided by Steve Venroy. Already released request
00037  * structure was passed to NutHttpSendError().
00038  *
00039  * Revision 1.14  2006/10/08 16:48:22  haraldkipp
00040  * Documentation fixed
00041  *
00042  * Revision 1.13  2006/03/16 15:25:38  haraldkipp
00043  * Changed human readable strings from u_char to char to stop GCC 4 from
00044  * nagging about signedness.
00045  *
00046  * Revision 1.12  2006/01/06 09:19:42  haraldkipp
00047  * NutHttpURLEncode() no longer encodes everything that isn't alphanumeric.
00048  * See RFC2396. Thanks to Lloyd Bailey for this update.
00049  *
00050  * Revision 1.11  2005/10/24 11:02:28  haraldkipp
00051  * Integer division hack for ARM without CRT removed.
00052  *
00053  * Revision 1.10  2005/08/26 14:12:39  olereinhardt
00054  * Added NutHttpProcessPostQuery(FILE *stream, REQUEST * req)
00055  *
00056  * Revision 1.9  2005/08/05 11:23:11  olereinhardt
00057  * Added support to register a custom handler for mime types.
00058  * Added Server side include support and ASP support.
00059  *
00060  * Revision 1.8  2005/04/30 13:08:15  chaac
00061  * Added support for parsing Content-Length field in HTTP requests.
00062  *
00063  * Revision 1.7  2005/04/05 17:58:02  haraldkipp
00064  * Avoid integer division on ARM platform as long as we run without crtlib.
00065  *
00066  * Revision 1.6  2004/12/16 10:17:18  haraldkipp
00067  * Added Mikael Adolfsson's excellent parameter parsing routines.
00068  *
00069  * Revision 1.5  2004/07/30 19:45:48  drsung
00070  * Slightly improved handling if socket was closed by peer.
00071  *
00072  * Revision 1.4  2004/03/02 10:09:59  drsung
00073  * Small bugfix in NutHttpSendError. Thanks to Damian Slee.
00074  *
00075  * Revision 1.3  2003/07/20 16:03:27  haraldkipp
00076  * Saved some RAM by moving string literals to program memory.
00077  *
00078  * Revision 1.2  2003/07/17 12:28:21  haraldkipp
00079  * Memory hole bugfix
00080  *
00081  * Revision 1.1.1.1  2003/05/09 14:41:58  haraldkipp
00082  * Initial using 3.2.1
00083  *
00084  * Revision 1.14  2003/02/04 18:17:32  harald
00085  * Version 3 released
00086  *
00087  * Revision 1.13  2003/01/14 17:04:20  harald
00088  * Using FAT file system and added types
00089  *
00090  * Revision 1.12  2002/10/31 16:32:45  harald
00091  * Mods by troth for Linux
00092  *
00093  * Revision 1.11  2002/09/15 17:08:44  harald
00094  * Allow different character sets
00095  *
00096  * Revision 1.10  2002/06/26 17:29:49  harald
00097  * First pre-release with 2.4 stack
00098  *
00099  */
00100 
00101 #include <cfg/arch.h>
00102 
00103 #include <string.h>
00104 #include <io.h>
00105 #include <fcntl.h>
00106 #include <ctype.h>
00107 #include <stdlib.h>
00108 
00109 #include <sys/heap.h>
00110 #include <sys/version.h>
00111 
00112 #include "dencode.h"
00113 
00114 #include <pro/httpd.h>
00115 
00120 
00121 static struct {
00122     char *ext;
00123     char *type;
00124     void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00125 } mimeTypes[] = {
00126     {
00127     ".txt", "text/plain", NULL}, {
00128     ".html", "text/html", NULL}, {
00129     ".shtml", "text/html", NULL}, {    
00130     ".asp", "text/html", NULL}, {
00131     ".htm", "text/html", NULL}, {
00132     ".gif", "image/gif", NULL}, {
00133     ".jpg", "image/jpeg", NULL}, {
00134     ".png", "image/png", NULL}, {    
00135     ".pdf", "application/pdf", NULL}, {
00136     ".js",  "application/x-javascript", NULL}, {
00137     ".css", "text/css", NULL}, {
00138     ".xml", "text/xml", NULL}
00139 };
00140 
00141 static char *http_root;
00142 
00154 void NutHttpSendHeaderTop(FILE * stream, REQUEST * req, int status, char *title)
00155 {
00156     static prog_char fmt_P[] = "HTTP/%d.%d %d %s\r\nServer: Ethernut %s\r\n";
00157 
00158     fprintf_P(stream, fmt_P, req->req_version / 10, req->req_version % 10, status, title, NutVersionString());
00159 }
00160 
00175 void NutHttpSendHeaderBot(FILE * stream, char *mime_type, long bytes)
00176 {
00177     static prog_char typ_fmt_P[] = "Content-Type: %s\r\n";
00178     static prog_char len_fmt_P[] = "Content-Length: %ld\r\n";
00179     static prog_char ccl_str_P[] = "Connection: close\r\n\r\n";
00180 
00181     if (mime_type)
00182         fprintf_P(stream, typ_fmt_P, mime_type);
00183     if (bytes >= 0)
00184         fprintf_P(stream, len_fmt_P, bytes);
00185     fputs_P(ccl_str_P, stream);
00186 }
00187 
00198 void NutHttpSendError(FILE * stream, REQUEST * req, int status)
00199 {
00200     static prog_char err_fmt_P[] = "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD><BODY>%d %s</BODY></HTML>";
00201     static prog_char auth_fmt_P[] = "WWW-Authenticate: Basic realm=\"%s\"\r\n";
00202     char *title;
00203 
00204     switch (status) {
00205     case 400:
00206         title = "Bad Request";
00207         break;
00208     case 401:
00209         title = "Unauthorized";
00210         break;
00211     case 404:
00212         title = "Not Found";
00213         break;
00214     case 500:
00215         title = "Internal Error";
00216         break;
00217     case 501:
00218         title = "Not Implemented";
00219         break;
00220     default:
00221         title = "Error";
00222         break;
00223     }
00224 
00225     NutHttpSendHeaderTop(stream, req, status, title);
00226     if (status == 401) {
00227         char *cp = 0;
00228         char *realm = req->req_url;
00229 
00230         if ((cp = strrchr(realm, '/')) != 0)
00231             *cp = 0;
00232         else
00233             realm = ".";
00234         fprintf_P(stream, auth_fmt_P, realm);
00235         if (cp)
00236             *cp = '/';
00237     }
00238     NutHttpSendHeaderBot(stream, "text/html", -1);
00239     fprintf_P(stream, err_fmt_P, status, title, status, title);
00240 }
00241 
00256 char *NutGetMimeType(char *name)
00257 {
00258     size_t i;
00259     int fl;
00260 
00261     if (name == 0 || (fl = strlen(name)) == 0)
00262         return mimeTypes[1].type;
00263     for (i = 0; i < sizeof(mimeTypes) / sizeof(*mimeTypes); i++)
00264         if (strcasecmp(&(name[fl - strlen(mimeTypes[i].ext)]), mimeTypes[i].ext) == 0)
00265             return mimeTypes[i].type;
00266     return mimeTypes[0].type;
00267 }
00268 
00284 void *NutGetMimeHandler(char *name)
00285 {
00286     size_t i;
00287     int fl;
00288 
00289     if (name == 0 || (fl = strlen(name)) == 0)
00290         return mimeTypes[1].handler;
00291     for (i = 0; i < sizeof(mimeTypes) / sizeof(*mimeTypes); i++)
00292         if (strcasecmp(&(name[fl - strlen(mimeTypes[i].ext)]), mimeTypes[i].ext) == 0)
00293             return mimeTypes[i].handler;
00294     return mimeTypes[0].handler;
00295 }
00296 
00308 u_char NutSetMimeHandler(char *extension, void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req))
00309 {
00310     size_t i;
00311 
00312     if (extension == NULL)
00313         return 1;
00314     for (i = 0; i < sizeof(mimeTypes) / sizeof(*mimeTypes); i++)
00315         if (strcasecmp(extension, mimeTypes[i].ext) == 0) {
00316             mimeTypes[i].handler = handler;
00317             return 0;
00318         }    
00319     return 1;
00320 }
00321 
00332 static char *hexdigits = "0123456789ABCDEF";
00333 
00334 char *NutHttpURLEncode(char *str)
00335 {
00336     register char *ptr1, *ptr2;
00337     char *encstring;
00338     int numEncs = 0;
00339 
00340     if (!str)
00341         return 0;
00342 
00343     /* Calculate how many characters we need to encode */
00344     for (ptr1 = str; *ptr1; ptr1++) {
00345         if (!isalnum(*ptr1) || *ptr1 == '%' || *ptr1 == '&'|| *ptr1 == '+' || 
00346         *ptr1 == ',' || *ptr1 == ':' || *ptr1 == ';'|| *ptr1 == '='|| *ptr1 == '?'|| *ptr1 == '@')
00347             numEncs++;
00348     }
00349     /* Now we can calculate the encoded string length */
00350     encstring = (char *) NutHeapAlloc(strlen(str) + 2 * numEncs + 1);
00351 
00352     /* Encode the string. ptr1 refers to the original string,
00353      * and ptr2 refers to the new string. */
00354     ptr2 = encstring;
00355     for (ptr1 = str; *ptr1; ptr1++) {
00356         if (isalnum(*ptr1) || *ptr1 == '%' || *ptr1 == '&'|| *ptr1 == '+' || 
00357         *ptr1 == ',' || *ptr1 == ':' || *ptr1 == ';'|| *ptr1 == '='|| *ptr1 == '?'|| *ptr1 == '@')
00358             *ptr2++ = *ptr1;
00359         else {
00360             *ptr2++ = '%';
00361             *ptr2++ = hexdigits[(*ptr1 >> 4)];
00362             *ptr2++ = hexdigits[*ptr1 & 0x0F];
00363         }
00364     }
00365     *ptr2++ = 0;
00366     return encstring;
00367 }
00368 
00380 void NutHttpURLDecode(char *str)
00381 {
00382     register char *ptr1, *ptr2, ch;
00383     char hexstr[3] = { 0, 0, 0 };
00384     for (ptr1 = ptr2 = str; *ptr1; ptr1++) {
00385         if (*ptr1 == '+')
00386             *ptr2++ = ' ';
00387         else if (*ptr1 == '%') {
00388             hexstr[0] = ptr1[1];
00389             hexstr[1] = ptr1[2];
00390             ch = strtol(hexstr, 0, 16);
00391             *ptr2++ = ch;
00392             ptr1 += 2;
00393         } else
00394             *ptr2++ = *ptr1;
00395     }
00396     *ptr2 = 0;
00397 }
00398 
00409 void NutHttpProcessQueryString(REQUEST * req)
00410 {
00411     register int i;
00412     register char *ptr;
00413 
00414     if (!req->req_query)
00415         return;
00416 
00417     req->req_numqptrs = 1;
00418     for (ptr = req->req_query; *ptr; ptr++)
00419         if (*ptr == '&')
00420             req->req_numqptrs++;
00421 
00422     req->req_qptrs = (char **) NutHeapAlloc(sizeof(char *) * (req->req_numqptrs * 2));
00423     if (!req->req_qptrs) {
00424         /* Out of memory */
00425         req->req_numqptrs = 0;
00426         return;
00427     }
00428     req->req_qptrs[0] = req->req_query;
00429     req->req_qptrs[1] = 0;
00430     for (ptr = req->req_query, i = 2; *ptr; ptr++) {
00431         if (*ptr == '&') {
00432             req->req_qptrs[i] = ptr + 1;
00433             req->req_qptrs[i + 1] = 0;
00434             *ptr = 0;
00435             i += 2;
00436         }
00437     }
00438 
00439     for (i = 0; i < req->req_numqptrs; i++) {
00440         for (ptr = req->req_qptrs[i * 2]; *ptr; ptr++) {
00441             if (*ptr == '=') {
00442                 req->req_qptrs[i * 2 + 1] = ptr + 1;
00443                 *ptr = 0;
00444                 NutHttpURLDecode(req->req_qptrs[i * 2 + 1]);
00445                 break;
00446             }
00447         }
00448         NutHttpURLDecode(req->req_qptrs[i * 2]);
00449     }
00450 }
00451 
00464 void NutHttpProcessPostQuery(FILE *stream, REQUEST * req)
00465 {
00466     register int i;
00467     register char *ptr;
00468     
00469     if (req->req_query != NULL)
00470         return;
00471     
00472     if (!stream)
00473         return;
00474     
00475     if (req->req_method == METHOD_POST) {
00476         req->req_query = NutHeapAllocClear(req->req_length+1);
00477         if (req->req_query == NULL) {
00478             /* Out of memory */
00479             req->req_numqptrs = 0;
00480             NutHeapFree(req->req_query);    
00481             return;            
00482         }
00483         i = 0;
00484         while (i < req->req_length) {
00485             i += fread(&req->req_query[i], 1, req->req_length-i, stream);
00486         }
00487     } else return;
00488 
00489     req->req_numqptrs = 1;
00490     for (ptr = req->req_query; *ptr; ptr++)
00491         if (*ptr == '&')
00492             req->req_numqptrs++;
00493 
00494     req->req_qptrs = (char **) NutHeapAlloc(sizeof(char *) * (req->req_numqptrs * 2));
00495     if (!req->req_qptrs) {
00496         /* Out of memory */
00497         req->req_numqptrs = 0;
00498         NutHeapFree(req->req_query);    
00499         return;
00500     }
00501     req->req_qptrs[0] = req->req_query;
00502     req->req_qptrs[1] = 0;
00503     for (ptr = req->req_query, i = 2; *ptr; ptr++) {
00504         if (*ptr == '&') {
00505             req->req_qptrs[i] = ptr + 1;
00506             req->req_qptrs[i + 1] = 0;
00507             *ptr = 0;
00508             i += 2;
00509         }
00510     }
00511 
00512     for (i = 0; i < req->req_numqptrs; i++) {
00513         for (ptr = req->req_qptrs[i * 2]; *ptr; ptr++) {
00514             if (*ptr == '=') {
00515                 req->req_qptrs[i * 2 + 1] = ptr + 1;
00516                 *ptr = 0;
00517                 NutHttpURLDecode(req->req_qptrs[i * 2 + 1]);
00518                 break;
00519             }
00520         }
00521         NutHttpURLDecode(req->req_qptrs[i * 2]);
00522     }
00523 }
00524 
00533 char *NutHttpGetParameter(REQUEST * req, char *name)
00534 {
00535     int i;
00536     for (i = 0; i < req->req_numqptrs; i++)
00537         if (strcmp(req->req_qptrs[i * 2], name) == 0)
00538             return req->req_qptrs[i * 2 + 1];
00539     return NULL;
00540 }
00541 
00549 int NutHttpGetParameterCount(REQUEST * req)
00550 {
00551     return req->req_numqptrs;
00552 }
00553 
00563 char *NutHttpGetParameterName(REQUEST * req, int index)
00564 {
00565     if (index < 0 || index >= NutHttpGetParameterCount(req))
00566         return NULL;
00567     return req->req_qptrs[index * 2];
00568 }
00569 
00579 char *NutHttpGetParameterValue(REQUEST * req, int index)
00580 {
00581     if (index < 0 || index >= NutHttpGetParameterCount(req))
00582         return NULL;
00583     return req->req_qptrs[index * 2 + 1];
00584 }
00585 
00586 static void NutHttpProcessFileRequest(FILE * stream, REQUEST * req)
00587 {
00588     int fd;
00589     int n;
00590     char *data;
00591     int size;
00592     long file_len;
00593     char *filename = NULL;
00594     void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req);
00595     
00596     /*
00597      * Validate authorization.
00598      */
00599     if (NutHttpAuthValidate(req)) {
00600         NutHttpSendError(stream, req, 401);
00601         return;
00602     }
00603 
00604     /*
00605      * Process CGI.
00606      */
00607     if (strncasecmp(req->req_url, "cgi-bin/", 8) == 0) {
00608         NutCgiProcessRequest(stream, req);
00609         return;
00610     }
00611 
00612     /*
00613      * Process file.
00614      */
00615     if (http_root) {
00616         filename = NutHeapAlloc(strlen(http_root) + strlen(req->req_url) + 1);
00617         strcpy(filename, http_root);
00618     } else {
00619         filename = NutHeapAlloc(strlen(req->req_url) + 6);
00620         strcpy(filename, "UROM:");
00621     }
00622     
00623     strcat(filename, req->req_url);
00624 
00625     handler = NutGetMimeHandler(filename);
00626 
00627     fd = _open(filename, _O_BINARY | _O_RDONLY);
00628     NutHeapFree(filename);
00629     if (fd == -1) {                     // Search for index.html
00630         char *index;
00631         u_short urll;
00632 
00633 
00634         urll = strlen(req->req_url);
00635         if ((index = NutHeapAllocClear(urll + 12)) == 0) {
00636             NutHttpSendError(stream, req, 500);
00637             return;
00638         }
00639         if (urll)
00640             strcpy(index, req->req_url);
00641         if (urll && index[urll - 1] != '/')
00642             strcat(index, "/");
00643         strcat(index, "index.html");
00644 
00645         if (http_root) {
00646             filename = NutHeapAlloc(strlen(http_root) + strlen(index) + 1);
00647             strcpy(filename, http_root);
00648         } else {
00649             filename = NutHeapAlloc(strlen(index) + 6);
00650             strcpy(filename, "UROM:");
00651         }
00652         strcat(filename, index);
00653 
00654         NutHeapFree(index);
00655 
00656         handler = NutGetMimeHandler(filename);
00657 
00658         fd = _open(filename, _O_BINARY | _O_RDONLY);
00659         NutHeapFree(filename);
00660         if (fd == -1) {                 // We have no index.html. But perhaps an index.shtml?
00661             urll = strlen(req->req_url);
00662             if ((index = NutHeapAllocClear(urll + 13)) == 0) {
00663                 NutHttpSendError(stream, req, 500);
00664                 return;
00665             }
00666             if (urll)
00667                 strcpy(index, req->req_url);
00668             if (urll && index[urll - 1] != '/')
00669                 strcat(index, "/");
00670             strcat(index, "index.shtml");
00671     
00672             if (http_root) {
00673                 filename = NutHeapAlloc(strlen(http_root) + strlen(index) + 1);
00674                 strcpy(filename, http_root);
00675             } else {
00676                 filename = NutHeapAlloc(strlen(index) + 6);
00677                 strcpy(filename, "UROM:");
00678             }
00679             strcat(filename, index);
00680     
00681             NutHeapFree(index);
00682 
00683             handler = NutGetMimeHandler(filename);
00684 
00685             fd = _open(filename, _O_BINARY | _O_RDONLY);
00686             NutHeapFree(filename);
00687             if (fd == -1) {            // Non of both found... send a 404
00688                 NutHttpSendError(stream, req, 404);
00689                 return;
00690             }
00691         }
00692     }
00693     
00694     file_len = _filelength(fd);
00695     if (handler == NULL) {
00696         NutHttpSendHeaderTop(stream, req, 200, "Ok");
00697         NutHttpSendHeaderBot(stream, NutGetMimeType(req->req_url), file_len);
00698         if (req->req_method != METHOD_HEAD) {
00699             size = 512;                 // If we have not registered a mime handler handle default.
00700             if ((data = NutHeapAlloc(size)) != 0) {
00701                 while (file_len) {
00702                     if (file_len < 512L)
00703                         size = (int) file_len;
00704     
00705                     n = _read(fd, data, size);
00706                     if (fwrite(data, 1, n, stream) == 0)
00707                         break;
00708                     file_len -= (long) n;
00709                 }
00710                 NutHeapFree(data);
00711             }
00712         }
00713     } else {
00714         NutHttpSendHeaderTop(stream, req, 200, "Ok");
00715         NutHttpSendHeaderBot(stream, NutGetMimeType(req->req_url), -1);
00716         handler(stream, fd, file_len, http_root, req);
00717     }
00718     _close(fd);
00719 }
00720 
00724 static char *NextWord(char *str)
00725 {
00726     while (*str && *str != ' ' && *str != '\t')
00727         str++;
00728     if (*str)
00729         *str++ = 0;
00730     while (*str == ' ' || *str == '\t')
00731         str++;
00732     return str;
00733 }
00734 
00738 static REQUEST *CreateRequestInfo(void)
00739 {
00740     return NutHeapAllocClear(sizeof(REQUEST));
00741 }
00742 
00746 static void DestroyRequestInfo(REQUEST * req)
00747 {
00748     if (req->req_url)
00749         NutHeapFree(req->req_url);
00750     if (req->req_query)
00751         NutHeapFree(req->req_query);
00752     if (req->req_type)
00753         NutHeapFree(req->req_type);
00754     if (req->req_cookie)
00755         NutHeapFree(req->req_cookie);
00756     if (req->req_auth)
00757         NutHeapFree(req->req_auth);
00758     if (req->req_agent)
00759         NutHeapFree(req->req_agent);
00760     if (req->req_qptrs)
00761         NutHeapFree(req->req_qptrs);
00762     NutHeapFree(req);
00763 }
00764 
00777 int NutRegisterHttpRoot(char *path)
00778 {
00779     int len;
00780 
00781     if (http_root)
00782         NutHeapFree(http_root);
00783     if (path && (len = strlen(path)) != 0) {
00784         if ((http_root = NutHeapAlloc(len + 1)) != 0)
00785             strcpy(http_root, path);
00786     } else
00787         http_root = 0;
00788 
00789     return 0;
00790 }
00791 
00801 void NutHttpProcessRequest(FILE * stream)
00802 {
00803     REQUEST *req;
00804     char *method;
00805     char *path;
00806     char *line;
00807     char *protocol;
00808     char *cp;
00809 
00810     /*
00811      * Parse the first line of the request.
00812      * <method> <path> <protocol>
00813      */
00814     if ((req = CreateRequestInfo()) == 0)
00815         return;
00816     if ((method = NutHeapAlloc(256)) == 0) {
00817         DestroyRequestInfo(req);
00818         return;
00819     }
00820     fgets(method, 256, stream);
00821     if ((cp = strchr(method, '\r')) != 0)
00822         *cp = 0;
00823     if ((cp = strchr(method, '\n')) != 0)
00824         *cp = 0;
00825 
00826     /*
00827      * Parse remaining request headers.
00828      */
00829     if ((line = NutHeapAlloc(256)) == 0) {
00830         NutHeapFree(method);
00831         DestroyRequestInfo(req);
00832         return;
00833     }
00834     for (;;) {
00835         if (fgets(line, 256, stream) == 0)
00836             break;
00837         if ((cp = strchr(line, '\r')) != 0)
00838             *cp = 0;
00839         if ((cp = strchr(line, '\n')) != 0)
00840             *cp = 0;
00841         if (*line == 0)
00842             break;
00843         if (strncasecmp(line, "Authorization:", 14) == 0) {
00844             if (req->req_auth == 0) {
00845                 cp = &line[14];
00846                 while (*cp == ' ' || *cp == '\t')
00847                     cp++;
00848                 if ((req->req_auth = NutHeapAlloc(strlen(cp) + 1)) == 0)
00849                     break;
00850                 strcpy(req->req_auth, cp);
00851             }
00852         } else if (strncasecmp(line, "Content-Length:", 15) == 0) {
00853             cp = &line[15];
00854             while (*cp == ' ' || *cp == '\t')
00855                 cp++;
00856             req->req_length = atoi(cp);
00857         } else if (strncasecmp(line, "Content-Type:", 13) == 0) {
00858             if (req->req_type == 0) {
00859                 cp = &line[13];
00860                 while (*cp == ' ' || *cp == '\t')
00861                     cp++;
00862                 if ((req->req_type = NutHeapAlloc(strlen(cp) + 1)) == 0)
00863                     break;
00864                 strcpy(req->req_type, cp);
00865             }
00866         } else if (strncasecmp(line, "Cookie:", 7) == 0) {
00867             if (req->req_cookie == 0) {
00868                 cp = &line[7];
00869                 while (*cp == ' ' || *cp == '\t')
00870                     cp++;
00871                 if ((req->req_cookie = NutHeapAlloc(strlen(cp) + 1)) == 0)
00872                     break;
00873                 strcpy(req->req_cookie, cp);
00874             }
00875         } else if (strncasecmp(line, "User-Agent:", 11) == 0) {
00876             if (req->req_agent == 0) {
00877                 cp = &line[11];
00878                 while (*cp == ' ' || *cp == '\t')
00879                     cp++;
00880                 if ((req->req_agent = NutHeapAlloc(strlen(cp) + 1)) == 0)
00881                     break;
00882                 strcpy(req->req_agent, cp);
00883             }
00884         }
00885     }
00886     NutHeapFree(line);
00887 
00888     path = NextWord(method);
00889     protocol = NextWord(path);
00890     NextWord(protocol);
00891 
00892     if (strcasecmp(method, "GET") == 0)
00893         req->req_method = METHOD_GET;
00894     else if (strcasecmp(method, "HEAD") == 0)
00895         req->req_method = METHOD_HEAD;
00896     else if (strcasecmp(method, "POST") == 0)
00897         req->req_method = METHOD_POST;
00898     else {
00899         NutHeapFree(method);
00900         NutHttpSendError(stream, req, 501);
00901         DestroyRequestInfo(req);
00902         return;
00903     }
00904     if (*path == 0 || *protocol == 0) {
00905         NutHeapFree(method);
00906         NutHttpSendError(stream, req, 400);
00907         DestroyRequestInfo(req);
00908         return;
00909     }
00910 
00911     req->req_version = 10;
00912     if (strcasecmp(protocol, "HTTP/0.9") == 0)
00913         req->req_version = 9;
00914 
00915     if ((cp = strchr(path, '?')) != 0) {
00916         *cp++ = 0;
00917         if ((req->req_query = NutHeapAlloc(strlen(cp) + 1)) == 0) {
00918             NutHeapFree(method);
00919             DestroyRequestInfo(req);
00920             return;
00921         }
00922         strcpy(req->req_query, cp);
00923 
00924         NutHttpProcessQueryString(req);
00925     }
00926 
00927     if ((req->req_url = NutHeapAlloc(strlen(path) + 1)) == 0) {
00928         NutHeapFree(method);
00929         DestroyRequestInfo(req);
00930         return;
00931     }
00932     strcpy(req->req_url, path);
00933 
00934     NutHeapFree(method);
00935 
00936     if (NutDecodePath(req->req_url) == 0) {
00937         NutHttpSendError(stream, req, 400);
00938     } else {
00939         NutHttpProcessFileRequest(stream, req);
00940     }
00941     DestroyRequestInfo(req);
00942 }
00943 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/