C – cgi编程
关于http通信的原理,在之前的http通讯和tinyhttpd —— C 语言实现最简单的 HTTP 服务器已经讲过。
对于编写cgi程序,我们最好还是使用cgic库比较好,以下程序只是提供理解cgic库的一种思路。
//cgitest.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
//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$
发表回复