|
|
1.1 moko 1: #ifndef PA_SAPI_INFO_H
2: #define PA_SAPI_INFO_H
3:
1.6 ! moko 4: #define IDENT_PA_SAPI_INFO_H "$Id: pa_sapi_info.h,v 1.5 2020/10/12 21:55:18 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: } *sapiInfo = NULL;
51:
52: class SAPI_Info_CGI : public SAPI_Info {
53: public:
54:
55: virtual size_t read_post(char *buf, size_t max_bytes) {
56: size_t read_size=0;
57: do {
58: ssize_t chunk_size=read(fileno(stdin), buf+read_size, min(READ_POST_CHUNK_SIZE, max_bytes-read_size));
59: if(chunk_size<=0)
60: break;
61: read_size+=chunk_size;
62: } while(read_size<max_bytes);
63: return read_size;
64: }
65:
66: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
67: SAPI_Info::add_header_attribute(dont_store_key, dont_store_value);
68: // if(!request || !request->console.was_used())
69: printf("%s: %s\n", capitalize(dont_store_key), dont_store_value);
70: }
71:
72: virtual void send_header() {
73: puts("");
74: }
75:
76:
77: };
78:
1.3 moko 79: char* replace_char(char* str, char from, char to){
80: for(char *pos = strchr(str,from); pos; pos=strchr(pos,from)) {
81: *pos = to;
82: }
83: return str;
84: }
85:
1.1 moko 86: class SAPI_Info_HTTPD : public SAPI_Info {
87: public:
88:
89: HTTPD_Connection &connection;
90: String output;
1.3 moko 91: HashStringString env;
1.1 moko 92:
93: SAPI_Info_HTTPD(HTTPD_Connection &aconnection) : connection(aconnection) {}
94:
1.3 moko 95: void populate_env() {
96: String::Body host("localhost");
1.2 moko 97: for(Array_iterator<HTTP_Headers::Header> i(connection.headers()); i.has_next(); ){
98: HTTP_Headers::Header header=i.next();
1.3 moko 99: String name("HTTP_");
100: name << replace_char(header.name.cstrm(), '-', '_');
101: String::Body value=header.value;
102:
103: if(header.name == "HOST"){
104: size_t port=value.pos(':');
105: if(port != STRING_NOT_FOUND)
106: value=value.mid(0, port);
107: host=value;
108: }
109: env.put(name, value);
1.1 moko 110: }
1.3 moko 111:
112: env.put("REQUEST_METHOD", connection.method());
113: env.put("REQUEST_URI", connection.uri());
114: env.put("QUERY_STRING", connection.query());
115:
116: env.put("SERVER_NAME", host);
117: env.put("REMOTE_ADDR", connection.remote_addr);
118:
1.1 moko 119: }
120:
1.3 moko 121: virtual char* get_env(const char* name) {
122: String::Body value = env.get(name);
123: return !value ? NULL : value.cstrm();
1.1 moko 124: }
125:
126: virtual const char* const *get_env() {
1.3 moko 127: const char** result=new(PointerGC) const char*[env.count()+1/*0*/];
1.1 moko 128: const char** cur=result;
1.3 moko 129: for(HashStringString::Iterator i(env); i; i.next()){
130: String pair;
131: pair << i.key() << "=" << i.value();
132: *cur++=pair.cstr();
1.1 moko 133: }
134: *cur=NULL;
135: return result;
136: }
137:
1.4 moko 138: virtual size_t read_post(char *buf, size_t max_bytes) {
139: return connection.read_post(buf, max_bytes);
1.1 moko 140: }
141:
142: virtual void add_header_attribute(const char* dont_store_key, const char* dont_store_value) {
143: if(strcasecmp(dont_store_key, "location")==0)
144: http_response_code=302;
145: if(strcasecmp(dont_store_key, HTTP_STATUS)==0)
146: http_response_code=atoi(dont_store_value);
147: else
148: output << capitalize(dont_store_key) << ": " << pa_strdup(dont_store_value) << "\r\n";
149: }
150:
1.6 ! moko 151: static const char *exception_http_status(const char *type) {
! 152: struct Lookup {
! 153: const char *code;
! 154: const char *type;
! 155: } static lookup[] = {
! 156: {"400", "httpd.request"},
! 157: {"404", "file.missing"},
! 158: {"408", "httpd.timeout"},
! 159: {"501", "httpd.method"},
! 160: { NULL, ""}
! 161: };
! 162: Lookup *cur = lookup;
! 163: for(; cur->code; cur++)
! 164: if(!strcmp(type, cur->type))
! 165: return cur->code;
! 166: return "500";
! 167: }
! 168:
! 169: static const char *status_message(int code) {
1.1 moko 170: struct Lookup {
171: int code;
172: const char *message;
173: } static lookup[] = {
174: {200, "OK"},
175: {206, "Partial Content"},
176: {301, "Moved Permanently"},
177: {302, "Found"},
1.6 ! moko 178: {304, "Not Modified"},
1.1 moko 179: {400, "Bad Request"},
180: {401, "Unauthorized"},
181: {403, "Forbidden"},
182: {404, "Not Found"},
1.6 ! moko 183: {408, "Request Timeout"},
1.1 moko 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 ");
1.6 ! moko 199: result << String::Body::Format(http_response_code) << " " << status_message(http_response_code) << "\r\n" << output << "\r\n";
1.1 moko 200: send_body(result.cstr(), result.length());
201: }
202:
203: virtual size_t send_body(const void *buf, size_t size) {
1.5 moko 204: return connection.send_body(buf, size);
1.1 moko 205: }
206:
207: };
208:
209: #endif