• 开源学习:tinyhttpd


    tinyhttpd 算是轻量级的http服务器,原版是linux代码,支持cgi脚本,我改了windows版本,去掉cgi脚本支持。添加了支持二级制文件下载,这样可以在本地测试下载东西了。

    // tinyhttpd.cpp : 定义控制台应用程序的入口点。
    //

    #include "stdafx.h"
    #include "windows.h"
    #include "winsock2.h"
    #include "WS2tcpip.h"
    #include <cstring>
    #include <io.h>
    #pragma comment(lib,"WS2_32.lib")

    #define ISspace(x) ((x) == ' ')

    #define SERVER_STRING "Server: jdbhttpd/0.1.0 "

    DWORD WINAPI accept_request(void*);
    void bad_request(int);
    void cat(int, FILE *);
    void cannot_execute(int);
    void error_die(const char *);
    int get_line(int, char *, int);
    void headers(int, const char *);
    void not_found(int);
    void serve_file(int, const char *);
    int startup(u_short *);
    void unimplemented(int);
    int strcasecmp(const char *pSrc,const char *pDst)
    {
    return stricmp(pSrc,pDst);
    }

    /**********************************************************************/
    /* A request has caused a call to accept() on the server port to
    * return. Process the request appropriately.
    * Parameters: the socket connected to the client */
    /**********************************************************************/
    DWORD WINAPI accept_request(void *para)
    {
    int client = (int)para;
    char buf[1024];
    int numchars;
    char method[255];
    char url[255];
    char path[512];
    size_t i, j;

    char *query_string = NULL;

    numchars = get_line(client, buf, sizeof(buf));
    i = 0; j = 0;
    while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
    {
    method[i] = buf[j];
    i++; j++;
    }
    method[i] = '';

    if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
    {
    unimplemented(client);
    return 0;
    }


    i = 0;
    while (ISspace(buf[j]) && (j < sizeof(buf)))
    j++;
    while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
    {
    url[i] = buf[j];
    i++; j++;
    }
    url[i] = '';

    if (strcasecmp(method, "GET") == 0)
    {
    query_string = url;
    while ((*query_string != '?') && (*query_string != ''))
    query_string++;
    if (*query_string == '?')
    {

    *query_string = '';
    query_string++;
    }
    }

    sprintf(path, "htdocs%s", url);
    if (path[strlen(path) - 1] == '/')
    strcat(path, "index.html");
    if (0 != _access(path,0))
    {
    while ((numchars > 0) && strcmp(" ", buf)) /* read & discard headers */
    numchars = get_line(client, buf, sizeof(buf));
    not_found(client);
    }
    else
    {
    serve_file(client, path);
    }

    closesocket(client);
    return 0;
    }

    /**********************************************************************/
    /* Inform the client that a request it has made has a problem.
    * Parameters: client socket */
    /**********************************************************************/
    void bad_request(int client)
    {
    char buf[1024];

    sprintf(buf, "HTTP/1.0 400 BAD REQUEST ");
    send(client, buf, sizeof(buf), 0);
    sprintf(buf, "Content-type: text/html ");
    send(client, buf, sizeof(buf), 0);
    sprintf(buf, " ");
    send(client, buf, sizeof(buf), 0);
    sprintf(buf, "<P>Your browser sent a bad request, ");
    send(client, buf, sizeof(buf), 0);
    sprintf(buf, "such as a POST without a Content-Length. ");
    send(client, buf, sizeof(buf), 0);
    }

    /**********************************************************************/
    /* Put the entire contents of a file out on a socket. This function
    * is named after the UNIX "cat" command, because it might have been
    * easier just to do something like pipe, fork, and exec("cat").
    * Parameters: the client socket descriptor
    * FILE pointer for the file to cat */
    #include "../../../Com/CFile.hpp"
    /**********************************************************************/
    void cat(int client, const char *resource)
    {
    Buf buf = MyReadFile(resource);
    if (buf.p)
    {
    send(client, buf.p,buf.size , 0);
    }
    }

    /**********************************************************************/
    /* Inform the client that a CGI script could not be executed.
    * Parameter: the client socket descriptor. */
    /**********************************************************************/
    void cannot_execute(int client)
    {
    char buf[1024];

    sprintf(buf, "HTTP/1.0 500 Internal Server Error ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "Content-type: text/html ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, " ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "<P>Error prohibited CGI execution. ");
    send(client, buf, strlen(buf), 0);
    }

    /**********************************************************************/
    /* Print out an error message with perror() (for system errors; based
    * on value of errno, which indicates system call errors) and exit the
    * program indicating an error. */
    /**********************************************************************/
    void error_die(const char *sc)
    {
    perror(sc);
    exit(1);
    }


    /**********************************************************************/
    /* Get a line from a socket, whether the line ends in a newline,
    * carriage return, or a CRLF combination. Terminates the string read
    * with a null character. If no newline indicator is found before the
    * end of the buffer, the string is terminated with a null. If any of
    * the above three line terminators is read, the last character of the
    * string will be a linefeed and the string will be terminated with a
    * null character.
    * Parameters: the socket descriptor
    * the buffer to save the data in
    * the size of the buffer
    * Returns: the number of bytes stored (excluding null) */
    /**********************************************************************/
    int get_line(int sock, char *buf, int size)
    {
    int i = 0;
    char c = '';
    int n;

    while ((i < size - 1) && (c != ' '))
    {
    n = recv(sock, &c, 1, 0);
    /* DEBUG printf("%02X ", c); */
    if (n > 0)
    {
    if (c == ' ')
    {
    n = recv(sock, &c, 1, MSG_PEEK);
    /* DEBUG printf("%02X ", c); */
    if ((n > 0) && (c == ' '))
    recv(sock, &c, 1, 0);
    else
    c = ' ';
    }
    buf[i] = c;
    i++;
    }
    else
    c = ' ';
    }
    buf[i] = '';

    return(i);
    }

    /**********************************************************************/
    /* Return the informational HTTP headers about a file. */
    /* Parameters: the socket to print the headers on
    * the name of the file */
    /**********************************************************************/
    void headers(int client, const char *filename)
    {
    char buf[1024];
    (void)filename; /* could use filename to determine file type */

    strcpy(buf, "HTTP/1.0 200 OK ");
    send(client, buf, strlen(buf), 0);
    strcpy(buf, SERVER_STRING);
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "Content-Type: application/octet-stream ");
    send(client, buf, strlen(buf), 0);
    strcpy(buf, " ");
    send(client, buf, strlen(buf), 0);
    }

    /**********************************************************************/
    /* Give a client a 404 not found status message. */
    /**********************************************************************/
    void not_found(int client)
    {
    char buf[1024];

    sprintf(buf, "HTTP/1.0 404 NOT FOUND ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, SERVER_STRING);
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "Content-Type: text/html ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, " ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "<HTML><TITLE>Not Found</TITLE> ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "<BODY><P>The server could not fulfill ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "your request because the resource specified ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "is unavailable or nonexistent. ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "</BODY></HTML> ");
    send(client, buf, strlen(buf), 0);
    }

    /**********************************************************************/
    /* Send a regular file to the client. Use headers, and report
    * errors to client if they occur.
    * Parameters: a pointer to a file structure produced from the socket
    * file descriptor
    * the name of the file to serve */
    /**********************************************************************/
    void serve_file(int client, const char *filename)
    {
    FILE *resource = NULL;
    int numchars = 1;
    char buf[1024];

    buf[0] = 'A'; buf[1] = '';
    while ((numchars > 0) && strcmp(" ", buf)) /* read & discard headers */
    numchars = get_line(client, buf, sizeof(buf));

    resource = fopen(filename, "rb");
    if (resource == NULL)
    not_found(client);
    else
    {
    headers(client, filename);
    cat(client, filename);
    }
    fclose(resource);
    }

    /**********************************************************************/
    /* This function starts the process of listening for web connections
    * on a specified port. If the port is 0, then dynamically allocate a
    * port and modify the original port variable to reflect the actual
    * port.
    * Parameters: pointer to variable containing the port to connect on
    * Returns: the socket */
    /**********************************************************************/
    int startup(u_short *port)
    {
    int httpd = 0;
    struct sockaddr_in name;

    httpd = socket(PF_INET, SOCK_STREAM, 0);
    if (httpd == -1)
    error_die("socket");
    memset(&name, 0, sizeof(name));
    name.sin_family = AF_INET;
    name.sin_port = htons(*port);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
    error_die("bind");
    if (*port == 0) /* if dynamically allocating a port */
    {
    int namelen = sizeof(name);
    if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1)
    error_die("getsockname");
    *port = ntohs(name.sin_port);
    }
    if (listen(httpd, 5) < 0)
    error_die("listen");
    return(httpd);
    }

    /**********************************************************************/
    /* Inform the client that the requested web method has not been
    * implemented.
    * Parameter: the client socket */
    /**********************************************************************/
    void unimplemented(int client)
    {
    char buf[1024];

    sprintf(buf, "HTTP/1.0 501 Method Not Implemented ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, SERVER_STRING);
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "Content-Type: text/html ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, " ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "</TITLE></HEAD> ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "<BODY><P>HTTP request method not supported. ");
    send(client, buf, strlen(buf), 0);
    sprintf(buf, "</BODY></HTML> ");
    send(client, buf, strlen(buf), 0);
    }

    /**********************************************************************/
    static void InitWinSock()
    {
    WSAData wsaData;
    WSAStartup(MAKEWORD(2, 1), &wsaData) ;

    }
    int main(void)
    {
    InitWinSock();
    int server_sock = -1;
    u_short port = 80;
    int client_sock = -1;
    struct sockaddr_in client_name;
    int client_name_len = sizeof(client_name);


    server_sock = startup(&port);
    printf("httpd running on port %d ", port);

    while (1)
    {
    client_sock = accept(server_sock,
    (struct sockaddr *)&client_name,
    &client_name_len);
    if (client_sock == -1)
    error_die("accept");
    CreateThread(0,0,accept_request,(void*)client_sock,0,0);

    }

    closesocket(server_sock);

    return(0);
    }

  • 相关阅读:
    Restful api 返回值重复的问题
    fastDFS遇到的并发问题recv cmd: 0 is not correct, expect cmd: 100
    忽略警告@SuppressWarnings的用法
    Mysql 一些命令记录
    python 操作excel实现替换特定内容
    python 提取目录中特定类型的文件
    python使用tkinter无法获取输入框的值
    python使用tkinter无法给顶层窗体的输入框设定默认值
    游戏基础知识第一弹
    python 3.7.4 安装 opencv
  • 原文地址:https://www.cnblogs.com/xujinping/p/4452095.html
Copyright © 2020-2023  润新知