|
|
1.1 moko 1: #ifndef PA_SAPI_INFO_H
2: #define PA_SAPI_INFO_H
3:
1.10 ! moko 4: #define IDENT_PA_SAPI_INFO_H "$Id: pa_sapi_info.h,v 1.9 2020/11/12 16:16:01 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:
1.7 moko 16: SAPI_Info() : http_response_code(200) {}
1.1 moko 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:
1.10 ! moko 25: virtual bool set_env(const char*, const char*) {
1.8 moko 26: return false;
27: }
28:
1.1 moko 29: virtual const char* const *get_env() {
30: #ifdef _MSC_VER
31: extern char **_environ;
32: return _environ;
33: #else
34: extern char **environ;
35: return environ;
36: #endif
37: }
38:
39: virtual size_t read_post(char *, size_t) {
40: return 0;
41: }
42:
43: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
44: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
45: http_response_code=atoi(dont_store_value);
46: }
47:
48: virtual void send_header() {}
49:
50: virtual size_t send_body(const void *buf, size_t size) {
51: return stdout_write(buf, size);
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:
81: };
82:
1.3 moko 83: char* replace_char(char* str, char from, char to){
84: for(char *pos = strchr(str,from); pos; pos=strchr(pos,from)) {
85: *pos = to;
86: }
87: return str;
88: }
89:
1.1 moko 90: class SAPI_Info_HTTPD : public SAPI_Info {
91: public:
92:
93: HTTPD_Connection &connection;
94: String output;
1.3 moko 95: HashStringString env;
1.1 moko 96:
97: SAPI_Info_HTTPD(HTTPD_Connection &aconnection) : connection(aconnection) {}
98:
1.3 moko 99: void populate_env() {
100: String::Body host("localhost");
1.2 moko 101: for(Array_iterator<HTTP_Headers::Header> i(connection.headers()); i.has_next(); ){
102: HTTP_Headers::Header header=i.next();
1.3 moko 103: String name("HTTP_");
104: name << replace_char(header.name.cstrm(), '-', '_');
105: String::Body value=header.value;
106:
107: if(header.name == "HOST"){
108: size_t port=value.pos(':');
109: if(port != STRING_NOT_FOUND)
110: value=value.mid(0, port);
111: host=value;
112: }
113: env.put(name, value);
1.1 moko 114: }
1.3 moko 115:
116: env.put("REQUEST_METHOD", connection.method());
117: env.put("REQUEST_URI", connection.uri());
118: env.put("QUERY_STRING", connection.query());
119:
120: env.put("SERVER_NAME", host);
121: env.put("REMOTE_ADDR", connection.remote_addr);
122:
1.1 moko 123: }
124:
1.3 moko 125: virtual char* get_env(const char* name) {
126: String::Body value = env.get(name);
127: return !value ? NULL : value.cstrm();
1.1 moko 128: }
129:
1.8 moko 130: virtual bool set_env(const char* name, const char* value) {
131: env.put(name, *new String(value));
132: return true;
133: }
134:
1.1 moko 135: virtual const char* const *get_env() {
1.3 moko 136: const char** result=new(PointerGC) const char*[env.count()+1/*0*/];
1.1 moko 137: const char** cur=result;
1.3 moko 138: for(HashStringString::Iterator i(env); i; i.next()){
139: String pair;
140: pair << i.key() << "=" << i.value();
141: *cur++=pair.cstr();
1.1 moko 142: }
143: *cur=NULL;
144: return result;
145: }
146:
1.4 moko 147: virtual size_t read_post(char *buf, size_t max_bytes) {
148: return connection.read_post(buf, max_bytes);
1.1 moko 149: }
150:
151: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
152: if(strcasecmp(dont_store_key, "location")==0)
153: http_response_code=302;
154: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
155: http_response_code=atoi(dont_store_value);
156: else
157: output << capitalize(dont_store_key) << ": " << pa_strdup(dont_store_value) << "\r\n";
158: }
159:
1.6 moko 160: static const char *exception_http_status(const char *type) {
161: struct Lookup {
162: const char *code;
163: const char *type;
164: } static lookup[] = {
165: {"400", "httpd.request"},
1.9 moko 166: {"400", "http.response"},
1.6 moko 167: {"404", "file.missing"},
168: {"408", "httpd.timeout"},
169: {"501", "httpd.method"},
170: { NULL, ""}
171: };
172: Lookup *cur = lookup;
173: for(; cur->code; cur++)
174: if(!strcmp(type, cur->type))
175: return cur->code;
176: return "500";
177: }
178:
179: static const char *status_message(int code) {
1.1 moko 180: struct Lookup {
181: int code;
182: const char *message;
183: } static lookup[] = {
184: {200, "OK"},
185: {206, "Partial Content"},
186: {301, "Moved Permanently"},
187: {302, "Found"},
1.6 moko 188: {304, "Not Modified"},
1.1 moko 189: {400, "Bad Request"},
190: {401, "Unauthorized"},
191: {403, "Forbidden"},
192: {404, "Not Found"},
1.6 moko 193: {408, "Request Timeout"},
1.1 moko 194: {500, "Internal Server Error"},
195: {501, "Not Implemented"},
196: {502, "Bad Gateway"},
197: {504, "Gateway Timeout"},
198: { 0, "Undescribed"}
199: };
200: Lookup *cur = lookup;
201: for(; cur->code; cur++)
202: if(code == cur->code)
203: return cur->message;
204: return cur->message;
205: }
206:
207: virtual void send_header() {
208: String result("HTTP/1.0 ");
1.6 moko 209: result << String::Body::Format(http_response_code) << " " << status_message(http_response_code) << "\r\n" << output << "\r\n";
1.1 moko 210: send_body(result.cstr(), result.length());
211: }
212:
213: virtual size_t send_body(const void *buf, size_t size) {
1.5 moko 214: return connection.send_body(buf, size);
1.1 moko 215: }
216:
217: };
218:
219: #endif