C - cgi编程

C - cgi编程

关于http通信的原理,在之前的http通讯tinyhttpd —— C 语言实现最简单的 HTTP 服务器已经讲过。

对于编写cgi程序,我们最好还是使用cgic库比较好,以下程序只是提供理解cgic库的一种思路。

//cgitest.c
#include 
#include 
#include 
#include 

#include "url.h"

int fgetlen(char *s, size_t len, FILE *stream)
{
    int count = 0;
    while (1) {
        s[count] = (char)fgetc(stream);
        --len;
        if (feof(stream) || (!(len - 1))) {
            count++;
            s[count] = '\0';
            break;
        }
        count++;
    }

    return count;
}

void handle_get()
{
    char *query_string = getenv("QUERY_STRING");
    char *getstring = url_decode(query_string);//url解码


    fprintf(stdout, "Content-type: application/json\n\n"); //必须加应答头,否则server会判断此程序不是cgi程序

    fprintf(stdout, "\"hello\":{\
            \"nihao\":\"你好\"\
            }\n");//stdout重定向到了请求端,所以printf打印到请求端

    if (getstring != NULL)
        url_free(getstring);
    return;
}

void handle_post()
{
    size_t content_lenth = atoi(getenv("CONTENT_LENGTH"));
    if (content_lenth == 0) {
        return;
    }
    char *input = (char *)malloc(content_lenth + 1);
    if (input == NULL)
        return;
    fgetlen(input, content_lenth + 1, stdin);
    char *poststring = url_decode(input);

    fprintf(stdout, "Content-type: application/json\n\n"); //必须加应答头,否则server会判断此程序不是cgi程序

    fprintf(stdout, "\"hello\":{\
            \"nihao\":\"你好\"\
            }\n");//stdout重定向到了请求端,所以printf打印到请求端

    if (poststring != NULL)
        url_free(poststring);
    return;
}

void handle_put()
{

}

void handle_delete()
{

}

int cgi_main()
{
    char *request_method = getenv("REQUEST_METHOD");

    if (request_method == NULL) {
        return EXIT_FAILURE;
    } else if (!strcasecmp(request_method, "GET")) {
        handle_get();
    } else if (!strcasecmp(request_method, "POST")) {
        handle_post();
    } else if (!strcasecmp(request_method, "PUT")) {
        handle_put();
    } else if (!strcasecmp(request_method, "DELETE")) {
        handle_delete();
    } else {
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}

int main(int argc, const char *argv[])
{
    return cgi_main();
}
//url.h
#ifndef __URL_H__
#define __URL_H__
char *url_encode(char url[]);
char *url_decode(char url[]);
void url_free(void *ptr);
#endif
//url.c
#include 
#include 
#include 
#include 

//two ways to use urldecode:
// urldecode stuff
// echo stuff | urldecode 

char *url_decode(const char *input)
{
    if (input == NULL)
        return NULL;
    int input_length = strlen(input);

    size_t output_length = (input_length + 1) * sizeof(char);
    char *working = malloc(output_length), *output = working;
    
    while(*input)
    {
        if(*input == '%')
        {
            char buffer[3] = { input[1], input[2], 0 };
            *working++ = strtol(buffer, NULL, 16);
            input += 3;
        }
        else
        {
            *working++ = *input++;
        }
    }

    *working = 0; //null terminate
    return output;
}


//two ways to use urlencode:
// urlencode stuff
// echo stuff | urlencode 

//note unicode support should happen upstream of this.
bool is_non_symbol(char c)
{
    if(c == '\0') return 1; //we want to write null regardless
    int c_int = (int)c;
    return (c_int >= 48 && c_int <= 57) || (c_int >= 65 && c_int <= 90) || (c_int >= 97 && c_int <= 122);
}

char *url_encode(const char *input)
{
    if (input == NULL)
        return NULL;
    int end = strlen(input);
    size_t final_size = (end * 3) + 1;
    char *working = malloc(final_size * sizeof(char)), *output = working;

    while(*input)
    {
        const char c = *input;
        if(c < 0)
        {
            input++;
        }
        else if(is_non_symbol(c)) 
        {
            *working++ = *input++;
        }
        else
        {
            char encoded[4] = {0};
            snprintf(encoded, 4, "%%%02x", c);

            *working++ = encoded[0];
            *working++ = encoded[1];
            *working++ = encoded[2];
            input++;
        }
    }

    *working = 0; //null term
    return output;
}

void url_free(void *ptr)
{
    free(ptr);
}

#if 0
int main(int argc, char **argv) 
{
    if(argc > 1)
    {
        char *input = argv[1];
        char *decoded = url_decode(input);
        printf("%s",decoded);
        url_free(decoded);
    }
    else
    {
        char *line = NULL;
        size_t size;
        while(getline(&line, &size, stdin) != -1)
        {
            char *decoded = url_decode(line);
            printf("%s", decoded);
            url_free(decoded);
        }
    }
    
    return 0;
}
#endif

#if 0
int main(int argc, char **argv) 
{
    if(argc > 1)
    {
        char *input = argv[1];
        char *encoded = url_encode(input);
        printf("%s", encoded);
        url_free(encoded);
    }
    else
    {
        char *line = NULL;
        size_t size;
        while(getline(&line, &size, stdin) != -1)
        {
            char *encoded = url_encode(line);
            printf("%s", encoded);
            url_free(encoded);
        }
    }
    return 0;
}
#endif

测试结果

jonathan@cloud:~/test/cgi$ ls
cgitest.c  url.c  url.h
jonathan@cloud:~/test/cgi$ gcc cgitest.c url.c -o cgitest
jonathan@cloud:~/test/cgi$ sudo cp cgitest /opt/thttpd/www/
jonathan@cloud:~/test/cgi$ curl 127.0.0.1/cgi-bin/cgitest
"hello":{            "nihao":"你好"            }
jonathan@cloud:~/test/cgi$ curl -H "Content-Type:application/json" -X POST --data '{"hello": "world"}' 127.0.0.1/cgi-bin/cgitest
"hello":{            "nihao":"你好"            }
jonathan@cloud:~/test/cgi$

你可能感兴趣的:(cgi,c)