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: