⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sws.c

📁 THIS IS HTTP CURL Example
💻 C
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************** *                                  _   _ ____  _ *  Project                     ___| | | |  _ \| | *                             / __| | | | |_) | | *                            | (__| |_| |  _ <| |___ *                             \___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * $Id: sws.c,v 1.110 2008-01-25 05:08:53 yangtse Exp $ ***************************************************************************//* sws.c: simple (silly?) web server   This code was originally graciously donated to the project by Juergen   Wilke. Thanks a bunch! */#include "setup.h" /* portability help from the lib directory */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <signal.h>#include <time.h>#include <sys/time.h>#include <sys/types.h>#include <ctype.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef _XOPEN_SOURCE_EXTENDED/* This define is "almost" required to build on HPUX 11 */#include <arpa/inet.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h> /* for TCP_NODELAY */#endif#define ENABLE_CURLX_PRINTF/* make the curlx header define all printf() functions to use the curlx_*   versions instead */#include "curlx.h" /* from the private lib dir */#include "getpart.h"#include "util.h"/* include memdebug.h last */#include "memdebug.h"#if !defined(CURL_SWS_FORK_ENABLED) && defined(HAVE_FORK)/* * The normal sws build for the plain standard curl test suite has no use for * fork(), but if you feel wild and crazy and want to setup some more exotic * tests. Define this and run... */#define CURL_SWS_FORK_ENABLED#endif#define REQBUFSIZ 150000#define REQBUFSIZ_TXT "149999"long prevtestno=-1; /* previous test number we served */long prevpartno=-1; /* previous part number we served */bool prevbounce;    /* instructs the server to increase the part number for                       a test in case the identical testno+partno request                       shows up again */#define RCMD_NORMALREQ 0 /* default request, use the tests file normally */#define RCMD_IDLE      1 /* told to sit idle */#define RCMD_STREAM    2 /* told to stream */struct httprequest {  char reqbuf[REQBUFSIZ]; /* buffer area for the incoming request */  int checkindex; /* where to start checking of the request */  int offset;     /* size of the incoming request */  long testno;     /* test number found in the request */  long partno;     /* part number found in the request */  int open;       /* keep connection open info, as found in the request */  bool auth_req;  /* authentication required, don't wait for body unless                     there's an Authorization header */  bool auth;      /* Authorization header present in the incoming request */  size_t cl;      /* Content-Length of the incoming request */  bool digest;    /* Authorization digest header found */  bool ntlm;      /* Authorization ntlm header found */  int pipe;       /* if non-zero, expect this many requests to do a "piped"                     request/response */  int rcmd;       /* doing a special command, see defines above */  int prot_version; /* HTTP version * 10 */  bool pipelining; /* true if request is pipelined */};int ProcessRequest(struct httprequest *req);void storerequest(char *reqbuf, ssize_t totalsize);#define DEFAULT_PORT 8999#ifndef DEFAULT_LOGFILE#define DEFAULT_LOGFILE "log/sws.log"#endifconst char *serverlogfile = DEFAULT_LOGFILE;#define SWSVERSION "cURL test suite HTTP server/0.1"#define REQUEST_DUMP  "log/server.input"#define RESPONSE_DUMP "log/server.response"/* very-big-path support */#define MAXDOCNAMELEN 140000#define MAXDOCNAMELEN_TXT "139999"#define REQUEST_KEYWORD_SIZE 256#define CMD_AUTH_REQUIRED "auth_required"/* 'idle' means that it will accept the request fine but never respond   any data. Just keep the connection alive. */#define CMD_IDLE "idle"/* 'stream' means to send a never-ending stream of data */#define CMD_STREAM "stream"#define END_OF_HEADERS "\r\n\r\n"enum {  DOCNUMBER_NOTHING = -7,  DOCNUMBER_QUIT    = -6,  DOCNUMBER_BADCONNECT = -5,  DOCNUMBER_INTERNAL= -4,  DOCNUMBER_CONNECT = -3,  DOCNUMBER_WERULEZ = -2,  DOCNUMBER_404     = -1};/* sent as reply to a QUIT */static const char *docquit ="HTTP/1.1 200 Goodbye" END_OF_HEADERS;/* sent as reply to a CONNECT */static const char *docconnect ="HTTP/1.1 200 Mighty fine indeed" END_OF_HEADERS;/* sent as reply to a "bad" CONNECT */static const char *docbadconnect ="HTTP/1.1 501 Forbidden you fool" END_OF_HEADERS;/* send back this on 404 file not found */static const char *doc404 = "HTTP/1.1 404 Not Found\r\n"    "Server: " SWSVERSION "\r\n"    "Connection: close\r\n"    "Content-Type: text/html"    END_OF_HEADERS    "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"    "<HTML><HEAD>\n"    "<TITLE>404 Not Found</TITLE>\n"    "</HEAD><BODY>\n"    "<H1>Not Found</H1>\n"    "The requested URL was not found on this server.\n"    "<P><HR><ADDRESS>" SWSVERSION "</ADDRESS>\n" "</BODY></HTML>\n";#ifdef SIGPIPEstatic volatile int sigpipe;  /* Why? It's not used */#endif#ifdef SIGPIPEstatic void sigpipe_handler(int sig){  (void)sig; /* prevent warning */  sigpipe = 1;}#endifint ProcessRequest(struct httprequest *req){  char *line=&req->reqbuf[req->checkindex];  char chunked=FALSE;  static char request[REQUEST_KEYWORD_SIZE];  static char doc[MAXDOCNAMELEN];  char logbuf[256];  int prot_major, prot_minor;  char *end;  int error;  end = strstr(line, END_OF_HEADERS);  logmsg("ProcessRequest() called");  /* try to figure out the request characteristics as soon as possible, but     only once! */  if((req->testno == DOCNUMBER_NOTHING) &&     sscanf(line, "%" REQBUFSIZ_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",            request,            doc,            &prot_major,            &prot_minor) == 4) {    char *ptr;    req->prot_version = prot_major*10 + prot_minor;    /* find the last slash */    ptr = strrchr(doc, '/');    /* get the number after it */    if(ptr) {      FILE *stream;      char *filename;      if((strlen(doc) + strlen(request)) < 200)        sprintf(logbuf, "Got request: %s %s HTTP/%d.%d",                request, doc, prot_major, prot_minor);      else        sprintf(logbuf, "Got a *HUGE* request HTTP/%d.%d",                prot_major, prot_minor);      logmsg("%s", logbuf);      if(!strncmp("/verifiedserver", ptr, 15)) {        logmsg("Are-we-friendly question received");        req->testno = DOCNUMBER_WERULEZ;        return 1; /* done */      }      if(!strncmp("/quit", ptr, 5)) {        logmsg("Request-to-quit received");        req->testno = DOCNUMBER_QUIT;        return 1; /* done */      }      ptr++; /* skip the slash */      /* skip all non-numericals following the slash */      while(*ptr && !ISDIGIT(*ptr))        ptr++;      req->testno = strtol(ptr, &ptr, 10);      if(req->testno > 10000) {        req->partno = req->testno % 10000;        req->testno /= 10000;      }      else        req->partno = 0;      sprintf(logbuf, "Requested test number %ld part %ld",              req->testno, req->partno);      logmsg("%s", logbuf);      filename = test2file(req->testno);      stream=fopen(filename, "rb");      if(!stream) {        error = ERRNO;        logmsg("fopen() failed with error: %d %s", error, strerror(error));        logmsg("Error opening file: %s", filename);        logmsg("Couldn't open test file %d", req->testno);        req->open = FALSE; /* closes connection */        return 1; /* done */      }      else {        char *cmd = NULL;        size_t cmdsize = 0;        int num=0;        /* get the custom server control "commands" */        cmd = (char *)spitout(stream, "reply", "servercmd", &cmdsize);        fclose(stream);        if(cmdsize) {          logmsg("Found a reply-servercmd section!");          if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) {            logmsg("instructed to require authorization header");            req->auth_req = TRUE;          }          else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) {            logmsg("instructed to idle");            req->rcmd = RCMD_IDLE;            req->open = TRUE;          }          else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) {            logmsg("instructed to stream");            req->rcmd = RCMD_STREAM;          }          else if(1 == sscanf(cmd, "pipe: %d", &num)) {            logmsg("instructed to allow a pipe size %d", num);            req->pipe = num-1; /* decrease by one since we don't count the                                  first request in this number */          }          free(cmd);        }      }    }    else {      if(sscanf(req->reqbuf, "CONNECT %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",                doc, &prot_major, &prot_minor) == 3) {        sprintf(logbuf, "Received a CONNECT %s HTTP/%d.%d request",                doc, prot_major, prot_minor);        logmsg("%s", logbuf);        if(req->prot_version == 10)          req->open = FALSE; /* HTTP 1.0 closes connection by default */        if(!strncmp(doc, "bad", 3))          /* if the host name starts with bad, we fake an error here */          req->testno = DOCNUMBER_BADCONNECT;        else if(!strncmp(doc, "test", 4)) {          /* if the host name starts with test, the port number used in the             CONNECT line will be used as test number! */          char *portp = strchr(doc, ':');          if(portp)            req->testno = atoi(portp+1);          else            req->testno = DOCNUMBER_CONNECT;        }        else          req->testno = DOCNUMBER_CONNECT;      }      else {        logmsg("Did not find test number in PATH");        req->testno = DOCNUMBER_404;      }    }  }  if(!end) {    /* we don't have a complete request yet! */    logmsg("ProcessRequest returned without a complete request");    return 0;  }  logmsg("ProcessRequest found a complete request");  if(req->pipe)    /* we do have a full set, advance the checkindex to after the end of the       headers, for the pipelining case mostly */    req->checkindex += (end - line) + strlen(END_OF_HEADERS);  /* **** Persistancy ****   *   * If the request is a HTTP/1.0 one, we close the connection unconditionally   * when we're done.   *   * If the request is a HTTP/1.1 one, we MUST check for a "Connection:"   * header that might say "close". If it does, we close a connection when   * this request is processed. Otherwise, we keep the connection alive for X   * seconds.   */  do {    if(!req->cl && curlx_strnequal("Content-Length:", line, 15)) {      /* If we don't ignore content-length, we read it and we read the whole         request including the body before we return. If we've been told to         ignore the content-length, we will return as soon as all headers         have been received */      req->cl = strtol(line+15, &line, 10);      logmsg("Found Content-Length: %d in the request", req->cl);      break;    }    else if(curlx_strnequal("Transfer-Encoding: chunked", line,                            strlen("Transfer-Encoding: chunked"))) {      /* chunked data coming in */      chunked = TRUE;    }    if(chunked) {      if(strstr(req->reqbuf, "\r\n0\r\n\r\n"))        /* end of chunks reached */        return 1; /* done */      else        return 0; /* not done */    }    line = strchr(line, '\n');    if(line)      line++;  } while(line);  if(!req->auth && strstr(req->reqbuf, "Authorization:")) {    req->auth = TRUE; /* Authorization: header present! */    if(req->auth_req)      logmsg("Authorization header found, as required");  }  if(!req->digest && strstr(req->reqbuf, "Authorization: Digest")) {    /* If the client is passing this Digest-header, we set the part number       to 1000. Not only to spice up the complexity of this, but to make       Digest stuff to work in the test suite. */    req->partno += 1000;    req->digest = TRUE; /* header found */    logmsg("Received Digest request, sending back data %d", req->partno);  }  else if(!req->ntlm &&          strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAD")) {    /* If the client is passing this type-3 NTLM header */    req->partno += 1002;    req->ntlm = TRUE; /* NTLM found */    logmsg("Received NTLM type-3, sending back data %d", req->partno);    if(req->cl) {      logmsg("  Expecting %d POSTed bytes", req->cl);    }  }  else if(!req->ntlm &&          strstr(req->reqbuf, "Authorization: NTLM TlRMTVNTUAAB")) {    /* If the client is passing this type-1 NTLM header */    req->partno += 1001;    req->ntlm = TRUE; /* NTLM found */    logmsg("Received NTLM type-1, sending back data %d", req->partno);  }  if(strstr(req->reqbuf, "Connection: close"))    req->open = FALSE; /* close connection after this request */  if(!req->pipe &&     req->open &&     req->prot_version >= 11 &&     end &&     req->reqbuf + req->offset > end + strlen(END_OF_HEADERS) &&     (!strncmp(req->reqbuf, "GET", strlen("GET")) ||      !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) {    /* If we have a persistent connection, HTTP version >= 1.1       and GET/HEAD request, enable pipelining. */    req->checkindex = (end - req->reqbuf) + strlen(END_OF_HEADERS);    req->pipelining = TRUE;  }  while(req->pipe) {    /* scan for more header ends within this chunk */    line = &req->reqbuf[req->checkindex];    end = strstr(line, END_OF_HEADERS);    if(!end)      break;    req->checkindex += (end - line) + strlen(END_OF_HEADERS);    req->pipe--;  }  /* If authentication is required and no auth was provided, end now. This     makes the server NOT wait for PUT/POST data and you can then make the     test case send a rejection before any such data has been sent. Test case     154 uses this.*/  if(req->auth_req && !req->auth)    return 1;  if(req->cl) {    if(req->cl <= req->offset - (end - req->reqbuf) - strlen(END_OF_HEADERS))      return 1; /* done */    else      return 0; /* not complete yet */  }  return 1; /* done */}/* store the entire request in a file */void storerequest(char *reqbuf, ssize_t totalsize){  int error;  ssize_t written;  ssize_t writeleft;  FILE *dump;  if (reqbuf == NULL)    return;  if (totalsize == 0)    return;  else if (totalsize < 0) {    logmsg("Invalid size (%d bytes) for request input. Not written to %s",           totalsize, REQUEST_DUMP);    return;  }  do {    dump = fopen(REQUEST_DUMP, "ab");  } while ((dump == NULL) && ((error = ERRNO) == EINTR));  if (dump == NULL) {    logmsg("Error opening file %s error: %d %s",           REQUEST_DUMP, error, strerror(error));    logmsg("Failed to write request input to " REQUEST_DUMP);    return;  }  writeleft = totalsize;  do {    written = (ssize_t)fwrite((void *) &reqbuf[totalsize-writeleft],                              1, (size_t)writeleft, dump);    if (written > 0)      writeleft -= written;  } while ((writeleft > 0) && ((error = ERRNO) == EINTR));  fclose(dump);  /* close it ASAP */  if (writeleft > 0) {    logmsg("Error writing file %s error: %d %s",           REQUEST_DUMP, error, strerror(error));    logmsg("Wrote only (%d bytes) of (%d bytes) request input to %s",           totalsize-writeleft, totalsize, REQUEST_DUMP);  }  else {    logmsg("Wrote request (%d bytes) input to " REQUEST_DUMP,           totalsize);  }}/* return 0 on success, non-zero on failure */static int get_request(curl_socket_t sock, struct httprequest *req){  int fail= FALSE;  char *reqbuf = req->reqbuf;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -