/* * Copyright (C) 2008 by egnite GmbH. All rights reserved. * Copyright (C) 2001-2007 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ */ /*! * \file pro/httpopt.c * \brief Optional HTTP routines. * * \verbatim * * $Log$ * Revision 1.4 2009/02/13 14:52:05 haraldkipp * Include memdebug.h for heap management debugging support. * * Revision 1.3 2008/08/11 07:00:35 haraldkipp * BSD types replaced by stdint types (feature request #1282721). * * Revision 1.2 2008/05/13 21:46:06 thiagocorrea * Fix a few documentation typos. * * Revision 1.1 2008/04/01 10:11:35 haraldkipp * Added the new, enhanced httpd API library. * Bugs #1839026 and #1839029 fixed. * * * \endverbatim */ #include #include #include #include #include #include #include #include #include #include "dencode.h" #include /*! * \addtogroup xgHTTPD */ /*@{*/ extern MIMETYPES mimeTypes[]; extern char *http_root; /*! * \brief Set the mime type handler for a specified file extension. * * This is the function that handles / sends a specific file type to the * client. Specially used for server side includes (shtml files) * * \param extension Filename extension the handler should be registered for * \param handler pointer to a function of the type void (u_char filename) * \return 1 on error or 0 on success */ uint8_t NutSetMimeHandler(char *extension, void (*handler)(FILE *stream, int fd, int file_len, char *http_root, REQUEST *req)) { size_t i; if (extension == NULL) return 1; for (i = 0; mimeTypes[i].mtyp_ext; i++) if (strcasecmp(extension, mimeTypes[i].mtyp_ext) == 0) { mimeTypes[i].mtyp_handler = handler; return 0; } return 1; } /*! * \brief URLEncodes a string * * \param str String to encode * * \return A new allocated encoded string, or NULL if str is null, or * if there's not enough memory for the new string. * * \note Remember to free() to the returned string. */ char *NutHttpURLEncode(char *str) { static char *hexdigits = "0123456789ABCDEF"; register char *ptr1, *ptr2; char *encstring; int numEncs = 0; if (!str) return NULL; /* Calculate how many characters we need to encode */ for (ptr1 = str; *ptr1; ptr1++) { if (!isalnum((unsigned char)*ptr1) || *ptr1 == '%' || *ptr1 == '&'|| *ptr1 == '+' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == ';'|| *ptr1 == '='|| *ptr1 == '?'|| *ptr1 == '@') numEncs++; } /* Now we can calculate the encoded string length */ encstring = (char *) malloc(strlen(str) + 2 * numEncs + 1); if (encstring) { /* Encode the string. ptr1 refers to the original string, * and ptr2 refers to the new string. */ ptr2 = encstring; for (ptr1 = str; *ptr1; ptr1++) { if (isalnum((unsigned char)*ptr1) || *ptr1 == '%' || *ptr1 == '&'|| *ptr1 == '+' || *ptr1 == ',' || *ptr1 == ':' || *ptr1 == ';'|| *ptr1 == '='|| *ptr1 == '?'|| *ptr1 == '@') *ptr2++ = *ptr1; else { *ptr2++ = '%'; *ptr2++ = hexdigits[(*ptr1 >> 4)]; *ptr2++ = hexdigits[*ptr1 & 0x0F]; } } *ptr2++ = 0; } return encstring; } /*! * \brief Parses the QueryString * * Reads the query from input stream and parses it into * name/value table. To save RAM, this method allocated ram and * uses req_query to store the input data. Then it creates a table * of pointers into the req_query buffer. * * \param stream Input stream * \param req Request object to parse */ void NutHttpProcessPostQuery(FILE *stream, REQUEST * req) { int got; register int i; register char *ptr; if (req->req_query != NULL) return; if (!stream) return; if (req->req_method == METHOD_POST) { req->req_query = malloc(req->req_length+1); if (req->req_query == NULL) { /* Out of memory */ req->req_numqptrs = 0; return; } memset(req->req_query, 0, req->req_length+1); i = 0; while (i < req->req_length) { got = fread(&req->req_query[i], 1, req->req_length-i, stream); if (got <= 0) { free(req->req_query); req->req_numqptrs = 0; req->req_query = NULL; return; } i += got; } } else return; req->req_numqptrs = 1; for (ptr = req->req_query; *ptr; ptr++) if (*ptr == '&') req->req_numqptrs++; req->req_qptrs = (char **) malloc(sizeof(char *) * (req->req_numqptrs * 2)); if (!req->req_qptrs) { /* Out of memory */ free(req->req_query); req->req_numqptrs = 0; req->req_query = NULL; return; } req->req_qptrs[0] = req->req_query; req->req_qptrs[1] = 0; for (ptr = req->req_query, i = 2; *ptr; ptr++) { if (*ptr == '&') { req->req_qptrs[i] = ptr + 1; req->req_qptrs[i + 1] = NULL; *ptr = 0; i += 2; } } for (i = 0; i < req->req_numqptrs; i++) { for (ptr = req->req_qptrs[i * 2]; *ptr; ptr++) { if (*ptr == '=') { req->req_qptrs[i * 2 + 1] = ptr + 1; *ptr = 0; NutHttpURLDecode(req->req_qptrs[i * 2 + 1]); break; } } NutHttpURLDecode(req->req_qptrs[i * 2]); } } /*! * \brief Gets a request parameter value by name * * \param req Request object * \param name Name of parameter * * \return Pointer to the parameter value. */ char *NutHttpGetParameter(REQUEST * req, char *name) { int i; for (i = 0; i < req->req_numqptrs; i++) if (strcmp(req->req_qptrs[i * 2], name) == 0) return req->req_qptrs[i * 2 + 1]; return NULL; } /*! * \brief Gets the number of request parameters * * The following code fragment retrieves all name/value pairs of the * request. * * \code * #include <pro/httpd.h> * * char *name; * char *value; * int i; * int n = NutHttpGetParameterCount(req); * * for (i = 0; i < n; i++) { * name = NutHttpGetParameterName(req, i); * value = NutHttpGetParameterValue(req, i); * } * \endcode * * \param req Request object * * \return The number of request parameters */ int NutHttpGetParameterCount(REQUEST * req) { return req->req_numqptrs; } /*! * \brief Gets the name of a request parameter * * \param req Request object * \param index Index of the requested parameter. * * \return Pointer to the parameter name at the given index, * or NULL if index is out of range. */ char *NutHttpGetParameterName(REQUEST * req, int index) { if (index < 0 || index >= NutHttpGetParameterCount(req)) return NULL; return req->req_qptrs[index * 2]; } /*! * \brief Get the value of a request parameter * * \param req Request object * \param index Index to the requested parameter. * * \return Pointer to the parameter value at the given index, * or NULL if index is out of range. */ char *NutHttpGetParameterValue(REQUEST * req, int index) { if (index < 0 || index >= NutHttpGetParameterCount(req)) return NULL; return req->req_qptrs[index * 2 + 1]; } /*@}*/