📄 gcgi.c
字号:
/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- *//* * GCGI Library, implementing NCSA'a Common Gateway Interface and RFC2338. * Copyright (C) 2001-2002 Julian Catchen, julian@catchen.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "gcgi_private.h"static const char* const envVars[] = { "HTTP_COOKIE", "HTTP_REFERER", "AUTH_TYPE", "CONTENT_LENGTH", "CONTENT_TYPE", "GATEWAY_INTERFACE", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_IDENT", "REMOTE_USER", "REQUEST_METHOD", "SCRIPT_NAME", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE" };#define ENVCOUNT 19/*------ Global Variables ------*/static CgiQuery *cgiQuery = NULL;static int debug = 0;static char *envVariablesFile = NULL;static char *cgiQueryFile = NULL;static size_t fieldLimit = 0;static size_t queryLimit = 0;static const char gcgi_ident[] = "$GCGI: GCGI " VERSION " Copyright (C) 2001-2002 Julian Catchen $\n" "$Authors: Julian Catchen, topeka@catchen.org $";gcgiReturnType initCgi( ) { int numBytes, gcgifd; if (debug) gcgiLoadEnvVariables(envVariablesFile); /* Dup stdout to gcgiOut */ gcgifd = dup(fileno(stdout)); gcgiOut = fdopen(gcgifd, "w"); /* Create the cgiQuery object. */ createCgiQuery(); if (cgiQuery->env[gcgiRequestMethod] == NULL ) return GCGIFATALERROR; if (! strncasecmp(cgiQuery->env[gcgiRequestMethod],"GET", 3) ) { parseGetQueryString(&numBytes); if (numBytes < 0) return GCGIFATALERROR; } else if (! strncasecmp(cgiQuery->env[gcgiRequestMethod],"POST", 4) ) { parsePostQueryString(&numBytes); if (numBytes < 0) return GCGIFATALERROR; } else return GCGIFATALERROR; return GCGISUCCESS;}void freeCgi( ){ freeCgiQuery(); if (envVariablesFile != NULL) XFREE(envVariablesFile); if (cgiQueryFile != NULL) XFREE(cgiQueryFile); }/* Limits specified in number of bytes. */gcgiReturnTypegcgiSetLimits(size_t flimit, size_t qlimit){ fieldLimit = flimit; queryLimit = qlimit; return GCGISUCCESS;}gcgiReturnType parsePostQueryString(int *numBytes){ FILE *input; char *querystring; size_t clen; int result; querystring = NULL; result = 0; /* Return if we don't have the content length env variable. */ if (cgiQuery->env[gcgiContentLength] == NULL || cgiQuery->env[gcgiContentType] == NULL) return GCGIFATALERROR; clen = strtol(cgiQuery->env[gcgiContentLength], NULL, 10); /* Content Length was out of range */ if (errno == ERANGE) return GCGIFATALERROR; if (debug) { if ((input = fopen(cgiQueryFile, "r")) == NULL) return GCGIFATALERROR; } else { input = stdin; } /* Standard URL Encoded POST string. */ if (strncasecmp(cgiQuery->env[gcgiContentType], "application/x-www-form-urlencoded", 33) == 0) { querystring = readQueryFromStream(input, clen); parseUrlEncoded(querystring, clen); *numBytes = clen; } /* RFC2388 Encoding */ else if (strncasecmp(cgiQuery->env[gcgiContentType], "multipart/form-data", 19) == 0) { /* Pass the file to the MIME library to parse. */ if ((result = parseFormData(input)) == GCGIFATALERROR) return GCGIFATALERROR; *numBytes = clen; } /* Unknown Encoding. */ else { fprintf(stderr,"Unknown Encoding.\n"); return GCGIFATALERROR; } if (debug) fclose(input); XFREE(querystring); if (result == GCGITRUNCATED) return GCGITRUNCATED; else return GCGISUCCESS;}gcgiReturnType parseGetQueryString(int *numBytes){ size_t clen; if (cgiQuery->env[gcgiQueryString] == NULL) return GCGIFATALERROR; clen = strlen(cgiQuery->env[gcgiQueryString]); if (clen <= 0) return GCGIFATALERROR; *numBytes = parseUrlEncoded(cgiQuery->env[gcgiQueryString], clen); return GCGISUCCESS;}gcgiReturnType parseUrlEncoded(char *querystring, int clen) { QueryStringNode *qstring; char *beg, *end, *qlen; char *offset, *p; int i; beg = end = qlen = NULL; offset = querystring + strlen(querystring); /* Count the number of fileds in the Query String. */ for (p = querystring, i = 0; p < offset; p++) if (*p == '&') i++; /* There is one more field than '&' characters. */ i++; /* Create the QueryStringColl Array */ createQueryStringCollArray(i); qlen = querystring + clen; for (beg = querystring; beg < qlen && end < qlen; beg = end+1) { /* Malloc the queryString object and initialize it. */ createQueryStringNode(&qstring); /* Get Field Name */ for (end = beg; *end != '=' && end < qlen; end++); qstring->field = XMALLOC(char, end - beg + 1); strncpy(qstring->field, beg, end-beg); qstring->field[end-beg] = '\0'; /* Zero out the string */ /* Get Data */ for (beg = end+1; *end != '&' && end < qlen; end++); qstring->data = XMALLOC(char, end - beg + 1); strncpy(qstring->data, beg, end-beg); qstring->data[end-beg] = '\0'; /* Zero out the string */ qstring->size = end - beg + 1; decodeUrl(qstring); /* Add struct to linked list. */ insertQueryStringNode(qstring); } /* for (beg = querystring; *beg < qlen && *end < qlen; beg++) */ return GCGISUCCESS;}gcgiReturnType parseFormData(FILE *data){ MimePart *mime, *n; QueryStringNode *node; int len, i, trunc; if ((mime = mimeParseMimeMessage(data, queryLimit, fieldLimit)) == NULL) return GCGIFATALERROR; /* Check if the MIME message was truncated. */ trunc = mime->truncated; /* Count the number of fileds in the Query String. */ for (n = mime->next, i = 0; n != NULL; n = n->next) i++; createQueryStringCollArray(i); for (n = mime->next; n != NULL; n = n->next) { createQueryStringNode(&node); len = strlen(n->name); node->field = XMALLOC(char, len + 1); strncpy(node->field, n->name, len); node->field[len] = '\0'; node->type = n->type; node->encoding = n->encoding; len = strlen(n->subtype); node->subtype = XMALLOC(char, len + 1); strncpy(node->subtype, n->subtype, len); node->subtype[len] = '\0'; if (n->filename != NULL) { len = strlen(n->filename); node->filename = XMALLOC(char, len + 1); strncpy(node->filename, n->filename, len); node->filename[len] = '\0'; } len = n->bodylen; node->data = XMALLOC(char, len + 1); /* Remove final "\r\n" that separated the boundary from the body. */ if (n->body[len-1] == '\n' && n->body[len-2] == '\r') len -= 2; memcpy(node->data, n->body, len); node->data[len] = '\0'; node->size = len; node->truncated = n->truncated; if (debug) fprintf(stderr,"N: Field: %s, Type: %d, Subtype: %s\n",n->name, n->type, n->subtype); insertQueryStringNode(node); node = NULL; } /* Free the MIME structures. */ mimeFreeMimeMessage(mime); if (trunc) return GCGITRUNCATED; else return GCGISUCCESS;}void decodeUrl(QueryStringNode *qstring){ char *f, *d; int flen, dlen; gcgiDecodeUrlEncodedString(qstring->field, &f, &flen); strncpy(qstring->field, f, flen); qstring->field[flen-1] = '\0'; gcgiDecodeUrlEncodedString(qstring->data, &d, &dlen); strncpy(qstring->data, d, dlen); qstring->data[dlen-1] = '\0'; XFREE(d); XFREE(f);}gcgiReturnType gcgiSendContentType(char *mimeType, char *name, char *charset, HTTPHeader header){ fprintf(gcgiOut, "Content-Type: %s", mimeType); if ( (charset!= NULL) && (strlen(charset) > 0) ) fprintf(gcgiOut, "; charset=\"%s\"", charset); if ( (name!= NULL) && (strlen(name) > 0) ) fprintf(gcgiOut, "; name=\"%s\"", name); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); return GCGISUCCESS;}gcgiReturnType gcgiSendContentDisp(MimeDisposition disp, char *filename, HTTPHeader header){ char *strDisp[] = { "inlined", "attachment", "formdata" }; fprintf(gcgiOut, "Content-Disposition: %s", strDisp[disp]); if ( (filename!= NULL) && (strlen(filename) > 0) ) fprintf(gcgiOut, "; filename=\"%s\"", filename); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); return GCGISUCCESS;}gcgiReturnType gcgiSendContentLength(int length, HTTPHeader header){ fprintf(gcgiOut, "Content-Length: %d", length); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); return GCGISUCCESS;}gcgiReturnType gcgiSendLocation(char *redirectURL){ fprintf(gcgiOut, "Location: %s\r\n\r\n", redirectURL); return GCGISUCCESS;}gcgiReturnType gcgiSendStatus(int status, char *message){ fprintf(gcgiOut, "HTTP/1.1 %d %s\r\n\r\n", status, message); return GCGISUCCESS;}gcgiReturnType gcgiSendCacheControl(char *cache, HTTPHeader header){ fprintf(gcgiOut, "Cache-Control: %s", cache); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); return GCGISUCCESS;}gcgiReturnType gcgiSendCookie(char *name, char *value, char *path, char *domain, char *expires, int secure, HTTPHeader header){ char *cookieEncoded; gcgiEncodeBaseSixtyFourString(value, strlen(value), &cookieEncoded); fprintf(gcgiOut, "Set-Cookie: %s=%s; path=%s; domain=%s;", name, cookieEncoded, path, domain); if (expires && strlen(expires) > 0) fprintf(gcgiOut, " expires=%s;", expires); if (secure) fprintf(gcgiOut, " secure"); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); XFREE(cookieEncoded); return GCGISUCCESS;}gcgiReturnType gcgiFetchCookies(char ***cookies){ tokenizeString(cgiQuery->env[gcgiHttpCookie], strlen(cgiQuery->env[gcgiHttpCookie]), cookies); return GCGISUCCESS;}gcgiReturnType gcgiParseCookie(char *cookie, char **name, char **value){ char *encoded, *decoded; int size; parseToken(cookie, name, &encoded); gcgiDecodeBaseSixtyFourString(encoded, &decoded, &size); size++; decoded = XREALLOC(char, decoded, size); decoded[size-1] = '\0'; *value = decoded; XFREE(encoded); return GCGISUCCESS;}gcgiReturnType gcgiFreeCookies(char **cookies){ freeStringArray(cookies); return GCGISUCCESS;}#ifdef USE_SSLgcgiReturnType gcgiSendEncryptedCookie(char *name, char *value, char *path, char *domain, char *expires, int secure, unsigned char *key, HTTPHeader header){ char *cookieEncoded; char *ciphertext, *digestEncoded; unsigned char *digest; int ctlen, dlen; ciphertext = NULL; digest = NULL; digestEncoded = NULL; ctlen = 0; dlen = 0; encryptString(value, strlen(value), key, &ciphertext, &ctlen); generateStringHMAC(ciphertext, ctlen, &digest, &dlen); gcgiEncodeBaseSixtyFourString(ciphertext, ctlen, &cookieEncoded); gcgiEncodeBaseSixtyFourString(digest, dlen, &digestEncoded); fprintf(gcgiOut, "Set-Cookie: %s=%s&%s; path=%s; domain=%s;", name, cookieEncoded, digestEncoded, path, domain); if (expires && strlen(expires) > 0) fprintf(gcgiOut, " expires=%s;", expires); if (secure) fprintf(gcgiOut, " secure"); if (header == LAST) fprintf(gcgiOut, "\r\n"); fprintf(gcgiOut, "\r\n"); XFREE(cookieEncoded); XFREE(ciphertext); XFREE(digest); XFREE(digestEncoded); return GCGISUCCESS;}gcgiReturnType gcgiParseEncryptedCookie(char *cookie, unsigned char *key, char **name, char **value){ char **tokens; int size; char *ciphertext, *cdigest, *encoded, *decoded; unsigned char *digest; int ctlen, dlen, cdlen; ciphertext = NULL; digest = NULL; cdigest = NULL; ctlen = 0; dlen = 0; cdlen = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -