📄 webs.c
字号:
websDone(wp, 0); } /* End of bugfix */ return -1; } else { /* Valid data *//* * Convert to UNICODE if necessary. First be sure the string * is NULL terminated. */ buf[nbytes] = '\0'; if ((text = ballocAscToUni(buf, nbytes)) == NULL) { websError(wp, 503, T("Insufficient memory")); return -1; } } } else {#ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { nbytes = websSSLGets(wp->wsp, &text); } else { nbytes = socketGets(wp->sid, &text); }#else nbytes = socketGets(wp->sid, &text);#endif if (nbytes < 0) { int eof;/* * Error, EOF or incomplete */#ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) {/* * If state is WEBS_BEGIN and the request is secure, a -1 will * usually indicate SSL negotiation */ if (wp->state == WEBS_BEGIN) { eof = 1; } else { eof = websSSLEof(wp->wsp); } } else { eof = socketEof(wp->sid); }#else eof = socketEof(wp->sid);#endif if (eof) {/* * If this is a post request without content length, process * the request as we now have all the data. Otherwise just * close the connection. */ if (wp->state == WEBS_POST) { websUrlHandlerRequest(wp); } else { websDone(wp, 0); } }/* * If state is WEBS_HEADER and the ringq is empty, then this is a * simple request with no additional header fields to process and * no empty line terminator. */ if (wp->state == WEBS_HEADER && ringqLen(&wp->header) <= 0) { websParseRequest(wp); websUrlHandlerRequest(wp); } return -1; } else if (nbytes == 0) { if (wp->state == WEBS_HEADER) {/* * Valid empty line, now finished with header */ websParseRequest(wp); if (wp->flags & WEBS_POST_REQUEST) { if (wp->flags & WEBS_CLEN) { wp->state = WEBS_POST_CLEN; clen = wp->clen; } else { wp->state = WEBS_POST; clen = 1; } if (clen > 0) {/* * Return 0 to get more data. */ return 0; } return 1; }/* * We've read the header so go and handle the request */ websUrlHandlerRequest(wp); } return -1; } } a_assert(text); a_assert(nbytes > 0); *ptext = text; *pnbytes = nbytes; return 1;}/******************************************************************************//* * Parse the first line of a HTTP request */static int websParseFirst(webs_t wp, char_t *text){ char_t *op, *proto, *protoVer, *url, *host, *query, *path, *port, *ext; char_t *buf; int testPort; a_assert(websValid(wp)); a_assert(text && *text);/* * Determine the request type: GET, HEAD or POST */ op = gstrtok(text, T(" \t")); if (op == NULL || *op == '\0') { websError(wp, 400, T("Bad HTTP request")); return -1; } if (gstrcmp(op, T("GET")) != 0) { if (gstrcmp(op, T("POST")) == 0) { wp->flags |= WEBS_POST_REQUEST; } else if (gstrcmp(op, T("HEAD")) == 0) { wp->flags |= WEBS_HEAD_REQUEST; } else { websError(wp, 400, T("Bad request type")); return -1; } }/* * Store result in the form (CGI) variable store */ websSetVar(wp, T("REQUEST_METHOD"), op); url = gstrtok(NULL, T(" \t\n")); if (url == NULL || *url == '\0') { websError(wp, 400, T("Bad HTTP request")); return -1; } protoVer = gstrtok(NULL, T(" \t\n"));/* * Parse the URL and store all the various URL components. websUrlParse * returns an allocated buffer in buf which we must free. We support both * proxied and non-proxied requests. Proxied requests will have http://host/ * at the start of the URL. Non-proxied will just be local path names. */ host = path = port = proto = query = ext = NULL; if (websUrlParse(url, &buf, &host, &path, &port, &query, &proto, NULL, &ext) < 0) { websError(wp, 400, T("Bad URL format")); return -1; } wp->url = bstrdup(B_L, url);#ifndef __NO_CGI_BIN if (gstrstr(url, CGI_BIN) != NULL) { wp->flags |= WEBS_CGI_REQUEST; if (wp->flags & WEBS_POST_REQUEST) { wp->cgiStdin = websGetCgiCommName(); } }#endif wp->query = bstrdup(B_L, query); wp->host = bstrdup(B_L, host); wp->path = bstrdup(B_L, path); wp->protocol = bstrdup(B_L, proto); wp->protoVersion = bstrdup(B_L, protoVer); if ((testPort = socketGetPort(wp->listenSid)) >= 0) { wp->port = testPort; } else { wp->port = gatoi(port); } if (gstrcmp(ext, T(".asp")) == 0) { wp->flags |= WEBS_ASP; } bfree(B_L, buf); websUrlType(url, wp->type, TSZ(wp->type));#if WEBS_PROXY_SUPPORT/* * Determine if this is a request for local webs data. If it is not a proxied * request from the browser, we won't see the "http://" or the system name, so * we assume it must be talking to us directly for local webs data. * Note: not fully implemented yet. */ if (gstrstr(wp->url, T("http://")) == NULL || ((gstrcmp(wp->host, T("localhost")) == 0 || gstrcmp(wp->host, websHost) == 0) && (wp->port == websPort))) { wp->flags |= WEBS_LOCAL_PAGE; if (gstrcmp(wp->path, T("/")) == 0) { wp->flags |= WEBS_HOME_PAGE; } }#endif ringqFlush(&wp->header); return 0;}/******************************************************************************//* * Parse a full request */#define isgoodchar(s) (gisalnum((s)) || ((s) == '/') || ((s) == '_') || \ ((s) == '.') || ((s) == '-') )static void websParseRequest(webs_t wp){ char_t *authType, *upperKey, *cp, *browser, *lp, *key, *value; a_assert(websValid(wp));/* * Define default CGI values */ websSetVar(wp, T("HTTP_AUTHORIZATION"), T(""));/* * Parse the header and create the Http header keyword variables * We rewrite the header as we go for non-local requests. NOTE: this * modifies the header string directly and tokenizes each line with '\0'. */ browser = NULL; for (lp = (char_t*) wp->header.servp; lp && *lp; ) { cp = lp; if ((lp = gstrchr(lp, '\n')) != NULL) { lp++; } if ((key = gstrtok(cp, T(": \t\n"))) == NULL) { continue; } if ((value = gstrtok(NULL, T("\n"))) == NULL) { value = T(""); } while (gisspace(*value)) { value++; } strlower(key);/* * Create a variable (CGI) for each line in the header */ fmtAlloc(&upperKey, (gstrlen(key) + 6), T("HTTP_%s"), key); for (cp = upperKey; *cp; cp++) { if (*cp == '-') *cp = '_'; } strupper(upperKey); websSetVar(wp, upperKey, value); bfree(B_L, upperKey);/* * Track the requesting agent (browser) type */ if (gstrcmp(key, T("user-agent")) == 0) { wp->userAgent = bstrdup(B_L, value);/* * Parse the user authorization. ie. password */ } else if (gstricmp(key, T("authorization")) == 0) {/* * Determine the type of Authorization Request */ authType = bstrdup (B_L, value); a_assert (authType);/* * Truncate authType at the next non-alpha character */ cp = authType; while (gisalpha(*cp)) { cp++; } *cp = '\0'; wp->authType = bstrdup(B_L, authType); bfree(B_L, authType); if (gstricmp(wp->authType, T("basic")) == 0) { char_t userAuth[FNAMESIZE];/* * The incoming value is username:password (Basic authentication) */ if ((cp = gstrchr(value, ' ')) != NULL) { *cp = '\0'; wp->authType = bstrdup(B_L, value); websDecode64(userAuth, ++cp, sizeof(userAuth)); } else { websDecode64(userAuth, value, sizeof(userAuth)); }/* * Split userAuth into userid and password */ if ((cp = gstrchr(userAuth, ':')) != NULL) { *cp++ = '\0'; } if (cp) { wp->userName = bstrdup(B_L, userAuth); wp->password = bstrdup(B_L, cp); } else { wp->userName = bstrdup(B_L, T("")); wp->password = bstrdup(B_L, T("")); }/* * Set the flags to indicate digest authentication */ wp->flags |= WEBS_AUTH_BASIC; } else {#ifdef DIGEST_ACCESS_SUPPORT/* * The incoming value is slightly more complicated (Digest) */ char_t *np; /* pointer to end of tag name */ char_t tp; /* temporary character holding space */ char_t *vp; /* pointer to value */ char_t *npv; /* pointer to end of value, "next" pointer */ char_t tpv; /* temporary character holding space *//* * Set the flags to indicate digest authentication */ wp->flags |= WEBS_AUTH_DIGEST;/* * Move cp to Next word beyond "Digest", * vp to first char after '='. */ cp = value; while (isgoodchar(*cp)) { cp++; } while (!isgoodchar(*cp)) { cp++; }/* * Find beginning of value */ vp = gstrchr(cp, '='); while (vp) {/* * Zero-terminate tag name */ np = cp; while (isgoodchar(*np)) { np++; } tp = *np; *np = 0;/* * Advance value pointer to first legit character */ vp++; while (!isgoodchar(*vp)) { vp++; }/* * Zero-terminate value */ npv = vp; while (isgoodchar(*npv)) { npv++; } tpv = *npv; *npv = 0;/* * Extract the fields */ if (gstricmp(cp, T("username")) == 0) { wp->userName = bstrdup(B_L, vp); } else if (gstricmp(cp, T("response")) == 0) { wp->digest = bstrdup(B_L, vp); } else if (gstricmp(cp, T("opaque")) == 0) { wp->opaque = bstrdup(B_L, vp); } else if (gstricmp(cp, T("uri")) == 0) { wp->uri = bstrdup(B_L, vp); } else if (gstricmp(cp, T("realm")) == 0) { wp->realm = bstrdup(B_L, vp); } else if (gstricmp(cp, T("nonce")) == 0) { wp->nonce = bstrdup(B_L, vp); } else if (gstricmp(cp, T("nc")) == 0) { wp->nc = bstrdup(B_L, vp); } else if (gstricmp(cp, T("cnonce")) == 0) { wp->cnonce = bstrdup(B_L, vp); } else if (gstricmp(cp, T("qop")) == 0) { wp->qop = bstrdup(B_L, vp); }/* * Restore tag name and value zero-terminations */ *np = tp; *npv = tpv;/* * Advance tag name and value pointers */ cp = npv; while (*cp && isgoodchar(*cp)) { cp++; } while (*cp && !isgoodchar(*cp)) { cp++; } if (*cp) { vp = gstrchr(cp, '='); } else { vp = NULL; } }#endif /* DIGEST_ACCESS_SUPPORT */ } /* if (gstrcmp(wp->authType)) *//* * Parse the content length */ } else if (gstrcmp(key, T("content-length")) == 0) { wp->flags |= WEBS_CLEN; wp->clen = gatoi(value); websSetVar(wp, T("CONTENT_LENGTH"), value);/* * Parse the content type */ } else if (gstrcmp(key, T("content-type")) == 0) { websSetVar(wp, T("CONTENT_TYPE"), value);#if WEBS_KEEP_ALIVE_SUPPORT } else if (gstrcmp(key, T("connection")) == 0) { strlower(value); if (gstrcmp(value, T("keep-alive")) == 0) { wp->flags |= WEBS_KEEP_ALIVE; }#endif#if WEBS_PROXY_SUPPORT/* * This may be useful if you wish to keep a local cache of web pages * for proxied requests. */ } else if (gstrcmp(key, T("pragma")) == 0) { char_t tmp[256]; gstrncpy(tmp, value, TSZ(tmp)); strlower(tmp); if (gstrstr(tmp, T("no-cache"))) { wp->flags |= WEBS_DONT_USE_CACHE; }#endif /* WEBS_PROXY_SUPPORT *//* * Store the cookie */ } else if (gstrcmp(key, T("cookie")) == 0) { wp->flags |= WEBS_COOKIE; wp->cookie = bstrdup(B_L, value);#if WEBS_IF_MODIFIED_SUPPORT/* * See if the local page has been modified since the browser last * requested this document. If not, just return a 302 */ } else if (gstrcmp(key, T("if-modified-since")) == 0) { char_t *cmd; time_t tip = 0; if ((cp = gstrchr(value, ';')) != NULL) { *cp = '\0'; } fmtAlloc(&cmd, 64, T("%s"), value); if ((wp->since = dateParse(tip, cmd)) != 0) { wp->flags |= WEBS_IF_MODIFIED; } bfreeSafe(B_L, cmd);#endif /* WEBS_IF_MODIFIED_SUPPORT */ } }}/******************************************************************************//* * Set the variable (CGI) environment for this request. Create variables * for all standard CGI variables. Also decode the query string and create * a variable for each name=value pair. */void websSetEnv(webs_t wp){ char_t portBuf[8]; char_t *keyword, *value, *valCheck, *valNew; a_assert(websValid(wp)); websSetVar(wp, T("QUERY_STRING"), wp->query); websSetVar(wp, T("GATEWAY_INTERFACE"), T("CGI/1.1")); websSetVar(wp, T("SERVER_HOST"), websHost); websSetVar(wp, T("SERVER_NAME"), websHost); websSetVar(wp, T("SERVER_URL"), websHostUrl); websSetVar(wp, T("REMOTE_HOST"), wp->ipaddr); websSetVar(wp, T("REMOTE_ADDR"), wp->ipaddr); websSetVar(wp, T("PATH_INFO"), wp->path); stritoa(websPort, portBuf, sizeof(portBuf)); websSetVar(wp, T("SERVER_PORT"), portBuf); websSetVar(wp, T("SERVER_ADDR"), websIpaddr); fmtAlloc(&value, FNAMESIZE, T("%s/%s"), WEBS_NAME, WEBS_VERSION); websSetVar(wp, T("SERVER_SOFTWARE"), value); bfreeSafe(B_L, value); websSetVar(wp, T("SERVER_PROTOCOL"), wp->protoVersion);/* * Decode and create an environment query variable for each query keyword. * We split into pairs at each '&', then split pairs at the '='. * Note: we rely on wp->decodedQuery preserving the decoded values in the * symbol table. */ wp->decodedQuery = bstrdup(B_L, wp->query); keyword = gstrtok(wp->decodedQuery, T("&")); while (keyword != NULL) { if ((value = gstrchr(keyword, '=')) != NULL) { *value++ = '\0'; websDecodeUrl(keyword, keyword, gstrlen(keyword)); websDecodeUrl(value, value, gstrlen(value)); } else { value = T(""); } if (*keyword) {/* * If keyword has already been set, append the new value to what has * been stored. */ if ((valCheck = websGetVar(wp, keyword, NULL)) != 0) { fmtAlloc(&valNew, 256, T("%s %s"), valCheck, value); websSetVar(wp, keyword, valNew); bfreeSafe(B_L, valNew); } else { websSetVar(wp, keyword, value); } } keyword = gstrtok(NULL, T("&")); }#if EMF/* * Add GoAhead Embedded Management Framework defines */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -