00001 /* 00002 * Copyright (C) 2001-2003 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: cgi.c,v $ 00035 * Revision 1.7 2008/08/22 09:23:56 haraldkipp 00036 * GCC specific implementation removed. 00037 * 00038 * Revision 1.6 2008/07/26 14:09:29 haraldkipp 00039 * Fixed another problem with ICCAVR. 00040 * 00041 * Revision 1.5 2008/07/25 12:17:26 olereinhardt 00042 * Imagecraft compilers does not support alloca (to allocate memory from the 00043 * stack). So we use NutHeapAlloc / NutHeapClear instead for Imagecraft. 00044 * 00045 * Revision 1.4 2008/07/17 11:33:32 olereinhardt 00046 * - Check for unique cgi names 00047 * - Alloc local copy of cgi name. Allows dynamicaly generated cgi names 00048 * - Function to register a different cgi-bin path. Multiple path allowed. 00049 * See httpd demo for an example 00050 * 00051 * Revision 1.3 2008/07/09 14:23:49 haraldkipp 00052 * Info about NutRegisterCgi's first parameter updated. 00053 * 00054 * Revision 1.2 2006/10/08 16:48:22 haraldkipp 00055 * Documentation fixed 00056 * 00057 * Revision 1.1.1.1 2003/05/09 14:41:56 haraldkipp 00058 * Initial using 3.2.1 00059 * 00060 * Revision 1.7 2003/02/04 18:17:31 harald 00061 * Version 3 released 00062 * 00063 * Revision 1.6 2002/06/26 17:29:49 harald 00064 * First pre-release with 2.4 stack 00065 * 00066 */ 00067 00068 #include <string.h> 00069 #include <sys/heap.h> 00070 00071 #include <pro/httpd.h> 00072 00077 00078 CGIFUNCTION *volatile cgiFunctionList = 0; 00079 char *cgiBinPath = NULL; 00080 00088 void NutRegisterCgiBinPath(char *path) 00089 { 00090 if (cgiBinPath) { 00091 NutHeapFree(cgiBinPath); 00092 } 00093 00094 cgiBinPath = NutHeapAlloc(strlen(path) + 1); 00095 strcpy(cgiBinPath, path); 00096 } 00097 00108 int NutCgiCheckRequest(FILE * stream, REQUEST * req) 00109 { 00110 /* 00111 * My version sticks with basic C routines. I hope, that it is also 00112 * faster and uses less memory. But it hasn't been tested very well, 00113 * so let's keep Ole's variant for GCC. 00114 */ 00115 size_t len; 00116 CONST char *cp; 00117 CONST char *cgi_bin = cgiBinPath ? cgiBinPath : "cgi-bin/"; 00118 00119 while (*cgi_bin) { 00120 /* Skip leading path separators. */ 00121 while (*cgi_bin == ';') 00122 cgi_bin++; 00123 /* Determine the length of the next path component. */ 00124 for (len = 0, cp = cgi_bin; *cp && *cp != ';'; len++, cp++); 00125 if (len) { 00126 /* Check if the URL starts with this component. If yes, run the CGI. */ 00127 if (strncasecmp(req->req_url, cgi_bin, len) == 0) { 00128 NutCgiProcessRequest(stream, req, len); 00129 return 1; 00130 } 00131 /* Try the next path component. */ 00132 cgi_bin += len; 00133 } 00134 } 00135 return 0; 00136 } 00137 00147 int NutRegisterCgi(char *name, int (*func) (FILE *, REQUEST *)) 00148 { 00149 int unique_name = 1; 00150 CGIFUNCTION *cgi; 00151 00152 cgi = cgiFunctionList; 00153 while (cgi != NULL) { 00154 if (strcmp(name, cgi->cgi_name) == 0) { 00155 unique_name = 0; 00156 break; 00157 } 00158 cgi = cgi->cgi_next; 00159 } 00160 00161 if ((!unique_name) || ((cgi = NutHeapAlloc(sizeof(CGIFUNCTION))) == 0)) { 00162 return -1; 00163 } 00164 cgi->cgi_next = cgiFunctionList; 00165 cgi->cgi_name = NutHeapAlloc(strlen(name)+1); 00166 strcpy(cgi->cgi_name, name); 00167 cgi->cgi_func = func; 00168 cgiFunctionList = cgi; 00169 00170 return 0; 00171 } 00172 00183 void NutCgiProcessRequest(FILE * stream, REQUEST * req, int name_pos) 00184 { 00185 CGIFUNCTION *cgi; 00186 00187 if (req->req_method != METHOD_GET && req->req_method != METHOD_POST) { 00188 NutHttpSendError(stream, req, 501); 00189 return; 00190 } 00191 00192 for (cgi = cgiFunctionList; cgi; cgi = cgi->cgi_next) { 00193 if (strcasecmp(cgi->cgi_name, req->req_url + name_pos) == 0) 00194 break; 00195 } 00196 if (cgi == 0) 00197 NutHttpSendError(stream, req, 404); 00198 else if ((*cgi->cgi_func) (stream, req)) 00199 NutHttpSendError(stream, req, 500); 00200 return; 00201 } 00202