Annotation of parser3/src/targets/cgi/pa_sapi_info.h, revision 1.18
1.1 moko 1: #ifndef PA_SAPI_INFO_H
2: #define PA_SAPI_INFO_H
3:
1.18 ! moko 4: #define IDENT_PA_SAPI_INFO_H "$Id: pa_sapi_info.h,v 1.17 2024/09/10 19:16:49 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:
1.12 moko 12: // for signal handlers and cgi console detection
13: static Request *request=0;
14:
15:
1.1 moko 16: class SAPI_Info : public PA_Allocated {
17: public:
18: int http_response_code;
19:
1.7 moko 20: SAPI_Info() : http_response_code(200) {}
1.1 moko 21:
22: virtual char* get_env(const char* name) {
23: if(char *local=getenv(name))
24: return pa_strdup(local);
25: else
26: return 0;
27: }
28:
1.10 moko 29: virtual bool set_env(const char*, const char*) {
1.8 moko 30: return false;
31: }
32:
1.1 moko 33: virtual const char* const *get_env() {
34: #ifdef _MSC_VER
35: extern char **_environ;
36: return _environ;
37: #else
38: extern char **environ;
39: return environ;
40: #endif
41: }
42:
43: virtual size_t read_post(char *, size_t) {
44: return 0;
45: }
46:
47: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
48: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
49: http_response_code=atoi(dont_store_value);
50: }
51:
52: virtual void send_header() {}
53:
54: virtual size_t send_body(const void *buf, size_t size) {
55: return stdout_write(buf, size);
56: }
57:
58: } *sapiInfo = NULL;
59:
60: class SAPI_Info_CGI : public SAPI_Info {
61: public:
62:
63: virtual size_t read_post(char *buf, size_t max_bytes) {
64: size_t read_size=0;
65: do {
66: ssize_t chunk_size=read(fileno(stdin), buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
67: if(chunk_size<=0)
68: break;
69: read_size+=chunk_size;
70: } while(read_size<max_bytes);
71: return read_size;
72: }
73:
74: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
75: SAPI_Info::add_header_attribute(dont_store_key, dont_store_value);
1.12 moko 76: if(!request || !request->console.was_used())
1.1 moko 77: printf("%s: %s\n", capitalize(dont_store_key), dont_store_value);
78: }
79:
80: virtual void send_header() {
81: puts("");
82: }
83:
84:
85: };
86:
1.3 moko 87: char* replace_char(char* str, char from, char to){
88: for(char *pos = strchr(str,from); pos; pos=strchr(pos,from)) {
89: *pos = to;
90: }
91: return str;
92: }
93:
1.1 moko 94: class SAPI_Info_HTTPD : public SAPI_Info {
95: public:
96:
97: HTTPD_Connection &connection;
1.14 moko 98: String::Body output;
1.3 moko 99: HashStringString env;
1.1 moko 100:
101: SAPI_Info_HTTPD(HTTPD_Connection &aconnection) : connection(aconnection) {}
102:
1.3 moko 103: void populate_env() {
104: String::Body host("localhost");
1.17 moko 105: for(Array_iterator<HTTP_Headers::Header> i(connection.headers()); i; ){
1.2 moko 106: HTTP_Headers::Header header=i.next();
1.3 moko 107: String name("HTTP_");
108: name << replace_char(header.name.cstrm(), '-', '_');
109: String::Body value=header.value;
110:
111: if(header.name == "HOST"){
112: size_t port=value.pos(':');
113: if(port != STRING_NOT_FOUND)
114: value=value.mid(0, port);
115: host=value;
116: }
117: env.put(name, value);
1.1 moko 118: }
1.3 moko 119:
120: env.put("REQUEST_METHOD", connection.method());
121: env.put("REQUEST_URI", connection.uri());
122: env.put("QUERY_STRING", connection.query());
123:
124: env.put("SERVER_NAME", host);
1.15 moko 125: env.put("SERVER_PORT", HTTPD_Server::port);
1.3 moko 126: env.put("REMOTE_ADDR", connection.remote_addr);
127:
1.1 moko 128: }
129:
1.3 moko 130: virtual char* get_env(const char* name) {
1.16 moko 131: String::Body request_value = env.get(name);
132: if(!request_value.is_empty())
133: return request_value.cstrm();
134: if(char *server_value=getenv(name))
135: return pa_strdup(server_value);
136: return NULL;
1.1 moko 137: }
138:
1.8 moko 139: virtual bool set_env(const char* name, const char* value) {
140: env.put(name, *new String(value));
141: return true;
142: }
143:
1.1 moko 144: virtual const char* const *get_env() {
1.3 moko 145: const char** result=new(PointerGC) const char*[env.count()+1/*0*/];
1.1 moko 146: const char** cur=result;
1.3 moko 147: for(HashStringString::Iterator i(env); i; i.next()){
148: String pair;
149: pair << i.key() << "=" << i.value();
150: *cur++=pair.cstr();
1.1 moko 151: }
152: *cur=NULL;
153: return result;
154: }
155:
1.4 moko 156: virtual size_t read_post(char *buf, size_t max_bytes) {
157: return connection.read_post(buf, max_bytes);
1.1 moko 158: }
159:
160: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
161: if(strcasecmp(dont_store_key, "location")==0)
162: http_response_code=302;
163: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
164: http_response_code=atoi(dont_store_value);
165: else
166: output << capitalize(dont_store_key) << ": " << pa_strdup(dont_store_value) << "\r\n";
167: }
168:
1.14 moko 169: void clear_response_headers() {
170: http_response_code=200;
171: output.clear();
172: }
173:
1.6 moko 174: static const char *exception_http_status(const char *type) {
175: struct Lookup {
176: const char *code;
177: const char *type;
178: } static lookup[] = {
1.13 moko 179: { "", "httpd.write"},
1.6 moko 180: {"400", "httpd.request"},
1.9 moko 181: {"400", "http.response"},
1.6 moko 182: {"404", "file.missing"},
183: {"408", "httpd.timeout"},
1.13 moko 184: {"408", "httpd.read"},
1.6 moko 185: {"501", "httpd.method"},
186: { NULL, ""}
187: };
188: Lookup *cur = lookup;
189: for(; cur->code; cur++)
190: if(!strcmp(type, cur->type))
191: return cur->code;
192: return "500";
193: }
194:
195: static const char *status_message(int code) {
1.1 moko 196: struct Lookup {
197: int code;
198: const char *message;
199: } static lookup[] = {
200: {200, "OK"},
1.11 moko 201: {204, "No Content"},
1.1 moko 202: {206, "Partial Content"},
203: {301, "Moved Permanently"},
204: {302, "Found"},
1.6 moko 205: {304, "Not Modified"},
1.1 moko 206: {400, "Bad Request"},
207: {401, "Unauthorized"},
208: {403, "Forbidden"},
209: {404, "Not Found"},
1.6 moko 210: {408, "Request Timeout"},
1.11 moko 211: {416, "Range Not Satisfiable"},
1.1 moko 212: {500, "Internal Server Error"},
213: {501, "Not Implemented"},
214: {502, "Bad Gateway"},
215: {504, "Gateway Timeout"},
216: { 0, "Undescribed"}
217: };
218: Lookup *cur = lookup;
219: for(; cur->code; cur++)
220: if(code == cur->code)
221: return cur->message;
222: return cur->message;
223: }
224:
225: virtual void send_header() {
226: String result("HTTP/1.0 ");
1.18 ! moko 227: result << pa_uitoa(http_response_code) << " " << status_message(http_response_code) << "\r\n" << output << "\r\n";
1.1 moko 228: send_body(result.cstr(), result.length());
229: }
230:
231: virtual size_t send_body(const void *buf, size_t size) {
1.5 moko 232: return connection.send_body(buf, size);
1.1 moko 233: }
234:
235: };
236:
237: #endif
E-mail: