Annotation of parser3/src/targets/cgi/pa_sapi_info.h, revision 1.6

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

E-mail: