Annotation of parser3/src/targets/cgi/pa_sapi_info.h, revision 1.3
1.1 moko 1: #ifndef PA_SAPI_INFO_H
2: #define PA_SAPI_INFO_H
3:
1.3 ! moko 4: #define IDENT_PA_SAPI_INFO_H "$Id: pa_sapi_info.h,v 1.2 2020/10/10 09:05:42 moko Exp $"
1.1 moko 5:
6: #include "pa_sapi.h"
7: #include "pa_http.h"
8:
9: /// IIS refuses to read bigger chunks
10: const size_t READ_POST_CHUNK_SIZE=0x400*0x400; // 1M
11:
12: class SAPI_Info : public PA_Allocated {
13: public:
14: int http_response_code;
15:
16: SAPI_Info() : http_response_code(0) {}
17:
18: virtual char* get_env(const char* name) {
19: if(char *local=getenv(name))
20: return pa_strdup(local);
21: else
22: return 0;
23: }
24:
25: virtual const char* const *get_env() {
26: #ifdef _MSC_VER
27: extern char **_environ;
28: return _environ;
29: #else
30: extern char **environ;
31: return environ;
32: #endif
33: }
34:
35: virtual size_t read_post(char *, size_t) {
36: return 0;
37: }
38:
39: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
40: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
41: http_response_code=atoi(dont_store_value);
42: }
43:
44: virtual void send_header() {}
45:
46: virtual size_t send_body(const void *buf, size_t size) {
47: return stdout_write(buf, size);
48: }
49:
50: virtual void die(const char *content, int content_length) {
51: stdout_write(content, content_length);
52: }
53:
54: } *sapiInfo = NULL;
55:
56: class SAPI_Info_CGI : public SAPI_Info {
57: public:
58:
59: virtual size_t read_post(char *buf, size_t max_bytes) {
60: size_t read_size=0;
61: do {
62: ssize_t chunk_size=read(fileno(stdin), buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
63: if(chunk_size<=0)
64: break;
65: read_size+=chunk_size;
66: } while(read_size<max_bytes);
67: return read_size;
68: }
69:
70: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
71: SAPI_Info::add_header_attribute(dont_store_key, dont_store_value);
72: // if(!request || !request->console.was_used())
73: printf("%s: %s\n", capitalize(dont_store_key), dont_store_value);
74: }
75:
76: virtual void send_header() {
77: puts("");
78: }
79:
80: virtual void die(const char *content, int content_length) {
81: // prepare header
82: // let's be honest, that's bad we couldn't produce valid output
83: // capitalized headers passed for preventing malloc during capitalization
84: add_header_attribute(HTTP_STATUS_CAPITALIZED, "500");
85: add_header_attribute(HTTP_CONTENT_TYPE_CAPITALIZED, "text/plain");
86: // don't use 'format' function because it calls malloc
87: char content_length_cstr[MAX_NUMBER];
88: snprintf(content_length_cstr, sizeof(content_length_cstr), "%u", content_length);
89: add_header_attribute(HTTP_CONTENT_LENGTH_CAPITALIZED, content_length_cstr);
90:
91: // send header
92: send_header();
93: // body
94: send_body(content, content_length);
95: }
96:
97: };
98:
1.3 ! moko 99: char* replace_char(char* str, char from, char to){
! 100: for(char *pos = strchr(str,from); pos; pos=strchr(pos,from)) {
! 101: *pos = to;
! 102: }
! 103: return str;
! 104: }
! 105:
1.1 moko 106: class SAPI_Info_HTTPD : public SAPI_Info {
107: public:
108:
109: HTTPD_Connection &connection;
110: String output;
1.3 ! moko 111: HashStringString env;
1.1 moko 112:
113: SAPI_Info_HTTPD(HTTPD_Connection &aconnection) : connection(aconnection) {}
114:
1.3 ! moko 115: void populate_env() {
! 116: String::Body host("localhost");
1.2 moko 117: for(Array_iterator<HTTP_Headers::Header> i(connection.headers()); i.has_next(); ){
118: HTTP_Headers::Header header=i.next();
1.3 ! moko 119: String name("HTTP_");
! 120: name << replace_char(header.name.cstrm(), '-', '_');
! 121: String::Body value=header.value;
! 122:
! 123: if(header.name == "HOST"){
! 124: size_t port=value.pos(':');
! 125: if(port != STRING_NOT_FOUND)
! 126: value=value.mid(0, port);
! 127: host=value;
! 128: }
! 129: env.put(name, value);
1.1 moko 130: }
1.3 ! moko 131:
! 132: env.put("REQUEST_METHOD", connection.method());
! 133: env.put("REQUEST_URI", connection.uri());
! 134: env.put("QUERY_STRING", connection.query());
! 135:
! 136: env.put("SERVER_NAME", host);
! 137: env.put("REMOTE_ADDR", connection.remote_addr);
! 138:
1.1 moko 139: }
140:
1.3 ! moko 141: virtual char* get_env(const char* name) {
! 142: String::Body value = env.get(name);
! 143: return !value ? NULL : value.cstrm();
1.1 moko 144: }
145:
146: virtual const char* const *get_env() {
1.3 ! moko 147: const char** result=new(PointerGC) const char*[env.count()+1/*0*/];
1.1 moko 148: const char** cur=result;
1.3 ! moko 149: for(HashStringString::Iterator i(env); i; i.next()){
! 150: String pair;
! 151: pair << i.key() << "=" << i.value();
! 152: *cur++=pair.cstr();
1.1 moko 153: }
154: *cur=NULL;
155: return result;
156: }
157:
158: virtual size_t read_post(char *, size_t) {
159: return 0;
160: }
161:
162: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
163: if(strcasecmp(dont_store_key, "location")==0)
164: http_response_code=302;
165: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
166: http_response_code=atoi(dont_store_value);
167: else
168: output << capitalize(dont_store_key) << ": " << pa_strdup(dont_store_value) << "\r\n";
169: }
170:
171: static const char *message(int code) {
172: struct Lookup {
173: int code;
174: const char *message;
175: } static lookup[] = {
176: {200, "OK"},
177: {206, "Partial Content"},
178: {301, "Moved Permanently"},
179: {302, "Found"},
180: {400, "Bad Request"},
181: {401, "Unauthorized"},
182: {403, "Forbidden"},
183: {404, "Not Found"},
184: {500, "Internal Server Error"},
185: {501, "Not Implemented"},
186: {502, "Bad Gateway"},
187: {504, "Gateway Timeout"},
188: { 0, "Undescribed"}
189: };
190: Lookup *cur = lookup;
191: for(; cur->code; cur++)
192: if(code == cur->code)
193: return cur->message;
194: return cur->message;
195: }
196:
197: virtual void send_header() {
198: String result("HTTP/1.0 ");
199: result << String::Body::Format(http_response_code) << " " << message(http_response_code) << "\r\n" << output << "\r\n";
200: send_body(result.cstr(), result.length());
201: }
202:
203: virtual size_t send_body(const void *buf, size_t size) {
204: if(send(connection.sock, buf, size, 0)!=(ssize_t)size) {
205: int no=pa_socks_errno();
206: throw Exception("httpd.timeout", 0, "error sending response: %s (%d)", pa_socks_strerr(no), no);
207: }
208: return size;
209: }
210:
211: };
212:
213: #endif
E-mail: