--- parser3/src/include/pa_request.h 2026/10/13 20:02:00 1.286 +++ parser3/src/include/pa_request.h 2026/10/28 01:17:38 1.293 @@ -8,7 +8,7 @@ #ifndef PA_REQUEST_H #define PA_REQUEST_H -#define IDENT_PA_REQUEST_H "$Id: pa_request.h,v 1.286 2026/10/13 20:02:00 moko Exp $" +#define IDENT_PA_REQUEST_H "$Id: pa_request.h,v 1.293 2026/10/28 01:17:38 moko Exp $" #include "pa_pool.h" #include "pa_hash.h" @@ -16,6 +16,7 @@ #include "pa_wcontext.h" #include "pa_value.h" #include "pa_vhash.h" +#include "pa_vresponse.h" #include "pa_stack.h" #include "pa_request_info.h" #include "pa_request_charsets.h" @@ -41,17 +42,18 @@ class Methoded; class VMethodFrame; class VMail; class VForm; -class VResponse; class VCookie; class VStateless_class; class VConsole; +class WebSocket; class VException; -extern int pa_loop_limit; -extern int pa_array_limit; -extern int pa_execute_recursion_limit; -extern int pa_httpd_timeout; -extern size_t pa_file_size_limit; +extern int pa_loop_limit; // not thread local: never changes +extern int pa_array_limit; // not thread local: never changes +extern int pa_execute_recursion_limit; // not thread local: never changes +extern int pa_httpd_timeout; // not thread local: never changes +extern THREAD_LOCAL size_t pa_file_size_limit; // thread local: url-dependent +extern THREAD_LOCAL size_t pa_post_max_size; // thread local: url-dependent class Code_cache; @@ -175,7 +177,8 @@ public: private: int fin_cycle; - Skip fskip; + volatile Skip fskip; // also changed from the signal handler + volatile int finterrupted; // set by the signal handler, if fskip was overwritten meanwhile, the next set_skip() restores SKIP_INTERRUPTED from it VMethodFrame* freturn_method_frame; public: @@ -212,8 +215,11 @@ public: */ void core(const char* config_filespec, const String& amain_method_name = main_method_name, const String* amain_class_name = NULL); - /// ^response:send[part]: the headers go with the first part, the result of @main or exception is not sent then - void send(Value& part); + /// ^response:stream[part]: the headers go with the first part + void stream(Value& part); + + /// sends headers and sets response.started + void start(VResponse::Started mode); /// executes ops void execute(ArrayOperation& ops); // execute.C @@ -324,10 +330,14 @@ public: } Skip get_skip() { return fskip; } - void set_skip(Skip askip) { fskip=askip; } - void set_skip_return(VMethodFrame& amethod_frame) { fskip=SKIP_RETURN; freturn_method_frame=&amethod_frame; } - inline bool check_skip_break() { bool result=fskip >= SKIP_BREAK; if(fskip <= SKIP_BREAK) fskip=SKIP_NOTHING; return result; } - inline void check_skip_return() { if(fskip==SKIP_RETURN && method_frame==freturn_method_frame) fskip=SKIP_NOTHING; } + void set_skip(Skip askip) { fskip=finterrupted ? SKIP_INTERRUPTED : askip; } + void set_skip_return(VMethodFrame& amethod_frame) { freturn_method_frame=&amethod_frame; set_skip(SKIP_RETURN); } + inline bool check_skip_break() { bool result=fskip >= SKIP_BREAK; if(fskip <= SKIP_BREAK) set_skip(SKIP_NOTHING); return result; } + inline void check_skip_return() { if(fskip==SKIP_RETURN && method_frame==freturn_method_frame) set_skip(SKIP_NOTHING); } + /// for signal handlers + void interrupt() { finterrupted=1; fskip=SKIP_INTERRUPTED; } + /// clears the interruption and throws parser.interrupted + void throw_interrupted(); void set_in_cycle(int adelta) { fin_cycle+=adelta; } bool get_in_cycle() { return fin_cycle>0; } @@ -355,6 +365,8 @@ public: VCookie& cookie; /// $console VConsole& console; + /// inited in httpd mode + WebSocket* websocket; /// classes configured data HashString classes_conf; @@ -412,13 +424,9 @@ private: // execute.C private: // mime types - /// $MAIN:MIME-TYPES + /// $MAIN:MIME-TYPES (table or @GET_MIME-TYPES[] property), built at the first use Table *mime_types; -private: // true if ^response:send[] was used - - bool fheaders_sent; - private: // connection manipulation SQL_Connection* set_connection(SQL_Connection* aconnection) {