Logo Search packages:      
Sourcecode: parser version File versions  Download package

static void _exec_cgi ( Request r,
MethodParams params,
bool  cgi 
) [static]

Todo:
fix `` in perl - they produced flipping consoles and no output to perl

Definition at line 367 of file file.C.

References Request::absolute(), String::append(), append_env_pair(), String::append_know_length(), MethodParams::as_no_junction(), Value::as_string(), Request::charsets, Request_info::content_length, Request_info::content_type, Array< T >::count(), String::cstr(), Request_info::document_root, SAPI::environment(), fix_line_breaks(), Array< T >::for_each(), Hash< K, V >::for_each(), Array< T >::get(), Charsets::get(), Value::get_hash(), Value::get_string(), Value::get_table(), Value::is_defined(), Value::is_string(), String::L_CLEAN, String::L_TAINTED, String::length(), MAX_NUMBER, Request_info::method, pa_exec(), pa_strdup(), Request_info::path_translated, Hash< K, V >::put(), Request_info::query_string, Request::request_info, Request::sapi_info, String::split(), STRING_NOT_FOUND, and Request_info::uri.

                                          {

      Value& first_param=params.as_no_junction(0, FIRST_ARG_MUST_NOT_BE_CODE);                  
      
      bool is_mode_specified=is_valid_mode(first_param.as_string());
      const String& mode_name=(is_mode_specified) ? first_param.as_string() : *new String(TEXT_MODE_NAME);

      size_t param_index=1;
      if(!is_mode_specified){
            --param_index;
      }

      if(param_index>=params.count())
            throw Exception(PARSER_RUNTIME,
                  0,
                  "file name must be specified");


      Value& vfile_name=params.as_no_junction(param_index++, FILE_NAME_MUST_NOT_BE_CODE);

      const String& script_name=r.absolute(vfile_name.as_string());

      HashStringString env;
      #define ECSTR(name, value_cstr) \
            if(value_cstr) \
                  env.put( \
                        String::Body(#name), \
                        String::Body(value_cstr, 0)); \
      // passing SAPI::environment
      if(const char *const *pairs=SAPI::environment(r.sapi_info)) {
            while(const char* pair=*pairs++)
                  if(const char* eq_at=strchr(pair, '='))
                        if(eq_at[1]) // has value
                              env.put(
                                    pa_strdup(pair, eq_at-pair),
                                    pa_strdup(eq_at+1, 0));
      }

      // const
      ECSTR(GATEWAY_INTERFACE, "CGI/1.1");
      // from Request.info
      ECSTR(DOCUMENT_ROOT, r.request_info.document_root);
      ECSTR(PATH_TRANSLATED, r.request_info.path_translated);
      ECSTR(REQUEST_METHOD, r.request_info.method);
      ECSTR(QUERY_STRING, r.request_info.query_string);
      ECSTR(REQUEST_URI, r.request_info.uri);
      ECSTR(CONTENT_TYPE, r.request_info.content_type);
      char content_length_cstr[MAX_NUMBER];  
      snprintf(content_length_cstr, MAX_NUMBER, "%u", r.request_info.content_length);
      //String content_length(content_length_cstr);
      ECSTR(CONTENT_LENGTH, content_length_cstr);
      // SCRIPT_*
      env.put(String::Body("SCRIPT_NAME"), script_name);
      //env.put(String::Body("SCRIPT_FILENAME"), ??&script_name);

      bool stdin_specified=false;
      // environment & stdin from param
      String *in=new String();
      Charset *charset=0; // default script works raw_in 'source' charset = no transcoding needed
      if(param_index < params.count()) {
            Value& venv=params.as_no_junction(param_index++, "env must not be code");
            if(HashStringValue* user_env=venv.get_hash()) {
                  // $.charset  [previewing to handle URI pieces]
                  if(Value* vcharset=user_env->get(CHARSET_EXEC_PARAM_NAME))
                        charset=&charsets.get(vcharset->as_string()
                              .change_case(r.charsets.source(), String::CC_UPPER));

                  // $.others
                  Append_env_pair_info info={&r.charsets, &env, 0};
                  {
                        // influence tainting
                        // main target -- $.QUERY_STRING -- URLencoding of tainted pieces to String::L_URI lang
                        Temp_client_charset temp(r.charsets, charset? *charset: r.charsets.source());
                        user_env->for_each<Append_env_pair_info*>(append_env_pair, &info);
                  }
                  // $.stdin
                  if(info.vstdin) {
                        stdin_specified=true;
                        if(const String* sstdin=info.vstdin->get_string()) {
                              in->append(*sstdin, String::L_CLEAN, true);
                        } else
                              if(VFile* vfile=static_cast<VFile *>(info.vstdin->as("file", false)))
                                    in->append_know_length((const char* )vfile->value_ptr(), vfile->value_size(), String::L_TAINTED);
                              else
                                    throw Exception(PARSER_RUNTIME,
                                          0,
                                          STDIN_EXEC_PARAM_NAME " parameter must be string or file");
                  }
            }
      }

      // argv from params
      ArrayString argv;
      if(param_index < params.count()) {
            // influence tainting 
            // main target -- URLencoding of tainted pieces to String::L_URI lang
            Temp_client_charset temp(r.charsets, charset? *charset: r.charsets.source());

            for(size_t i=param_index; i<params.count(); i++) {
                  Value& param=params.as_no_junction(i, PARAM_MUST_NOT_BE_CODE);
                  if(param.is_defined()){
                        if(param.is_string()){
                              append_to_argv(r, argv, param.get_string());
                        } else {
                              Table* table=param.get_table();
                              if(table){
                                    for(size_t i=0; i<table->count(); i++) {
                                          append_to_argv(r, argv, table->get(i)->get(0));
                                    }
                              } else {
                                    throw Exception(PARSER_RUNTIME,
                                          0,
                                          "param must be string or table");
                              }
                        }
                  }
            }
      }

      // transcode if necessary
      if(charset) {
            Charset::transcode(env, r.charsets.source(), *charset);
            Charset::transcode(argv, r.charsets.source(), *charset);
            in=&Charset::transcode(*in, r.charsets.source(), *charset);
      }
      // @todo 
      // ifdef WIN32 do  OEM->ANSI transcode on some(.cmd?) programs to 
      // match silent conversion in OS

      // exec!
      PA_exec_result execution=pa_exec(false/*forced_allow*/, script_name, &env, argv, *in);

      File_read_result *file_out=&execution.out;
      String *real_err=&execution.err;

      // transcode err if necessary (@todo: need fix line breaks in err as well )
      if(charset)
            real_err=&Charset::transcode(*real_err, *charset, r.charsets.source());

      if(file_out->length && is_text_mode(mode_name)){
            fix_line_breaks(file_out->str, file_out->length);
            // treat output as string
            String *real_out = new String(file_out->str, file_out->length);

            // transcode out if necessary
            if(charset)
                  real_out=&Charset::transcode(*real_out, *charset, r.charsets.source());

            // FIXME: unsafe cast
            file_out->str=const_cast<char *>(real_out->cstr()); // hacking a little
            file_out->length = real_out->length();
      }

      VFile& self=GET_SELF(r, VFile);

      if(cgi) { // ^file::cgi
            const char* eol_marker=0;
            size_t eol_marker_size;

            // construct with 'out' body and header
            size_t dos_pos=(file_out->length)?strpos(file_out->str, "\r\n\r\n"):STRING_NOT_FOUND;
            size_t unix_pos=(file_out->length)?strpos(file_out->str, "\n\n"):STRING_NOT_FOUND;

            bool unix_header_break;
            switch((dos_pos!=STRING_NOT_FOUND?10:00) + (unix_pos!=STRING_NOT_FOUND?01:00)) {
                  case 10: // dos
                        unix_header_break=false;
                        break;
                  case 01: // unix
                        unix_header_break=true;
                        break;
                  case 11: // dos & unix
                        unix_header_break=unix_pos<dos_pos;
                        break;
                  default: // 00
                        unix_header_break=false; // calm down, compiler
                        throw Exception("file.execute",
                              0,
                              "output does not contain CGI header; "
                              "exit status=%d; stdoutsize=%u; stdout: \"%s\"; stderrsize=%u; stderr: \"%s\"", 
                                    execution.status, 
                                    (size_t)file_out->length, (file_out->length) ? (file_out->str) : "",
                                    (size_t)real_err->length(), real_err->cstr());
                        break; //never reached
            }

            size_t header_break_pos;
            if(unix_header_break) {
                  header_break_pos=unix_pos;
                  eol_marker="\n";
                  eol_marker_size=1;
            } else {
                  header_break_pos=dos_pos;
                  eol_marker="\r\n";
                  eol_marker_size=2;
            }

            file_out->str[header_break_pos] = 0;
            String *header=new String(file_out->str, header_break_pos);
            unsigned long headersize = header_break_pos+eol_marker_size*2;
            file_out->str += headersize;
            file_out->length -= headersize;

            // $body
            self.set(false/*not tainted*/, file_out->str, file_out->length);

            // $fields << header
            if(header && eol_marker) {
                  ArrayString rows;
                  size_t pos_after=0;
                  header->split(rows, pos_after, eol_marker);
                  Pass_cgi_header_attribute_info info={0, 0, 0};
                  info.charset=&r.charsets.source();
                  info.fields=&self.fields();
                  rows.for_each(pass_cgi_header_attribute, &info);
                  if(info.content_type)
                        self.fields().put(content_type_name, info.content_type);
            }
      } else { // ^file::exec
            // $body
            self.set(false/*not tainted*/, file_out->str, file_out->length);
      }

      // $status
      self.fields().put(file_status_name, new VInt(execution.status));
      
      // $stderr
      if(real_err->length())
            self.fields().put(
                  String::Body("stderr"),
                  new VString(*real_err));
}


Generated by  Doxygen 1.6.0   Back to index