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