/***
 * The main request handler.
 **/
static int
mapserver_handler (request_rec *r)
{
  /* aquire the apropriate configuration for this directory */
  mapserver_dir_config *conf;
  conf = (mapserver_dir_config*) ap_get_module_config (r->per_dir_config,
         &mapserver_module);

  /* decline the request if there's no map configured */
  if (!conf || !conf->map)
    return DECLINED;

  apr_finfo_t mapstat;
  if (apr_stat (&mapstat, conf->mapfile_name, APR_FINFO_MTIME, r->pool) == APR_SUCCESS) {
    if (apr_time_sec (mapstat.mtime) > apr_time_sec (conf->mtime)) {
      mapObj *newmap = msLoadMap (conf->mapfile_name, NULL);
      if (newmap) {
        msFreeMap (conf->map);
        conf->map   = newmap;
        conf->mtime = mapstat.mtime;
      } else {
        ap_log_error (APLOG_MARK, APLOG_WARNING, 0, NULL,
                      "unable to reload map file %s", conf->mapfile_name);
      }
    }
  } else {
    ap_log_error (APLOG_MARK, APLOG_WARNING, 0, NULL,
                  "%s: unable to stat file %s", __func__, conf->mapfile_name);
  }

  /* make a copy of the URI so we can modify it safely */
  char *uri          = apr_pstrdup (r->pool, r->uri);
  int   len          = strlen (uri);
  int   conf_uri_len = strlen (conf->uri);

  /* If the URI points to a subdirectory we want to decline.
   */
  if (len > conf_uri_len)
    return DECLINED;

  int    argc          = 0;
  char **ParamNames    = NULL;
  char **ParamValues   = NULL;
  char  *post_data     = NULL;
  int    szMethod      = -1;
  char  *szContentType = NULL;
  mapservObj *mapserv = NULL;

  /* Try decoding the query string */
  if (r->method_number == M_GET) {
    argc = mapserver_decode_args (r->pool, (char*) apr_pstrdup (r->pool, r->args),
                                  &ParamNames, &ParamValues);
    szMethod = MS_GET_REQUEST;
  } else if (r->method_number == M_POST) {
    szContentType = (char*) apr_table_get (r->headers_in, "Content-Type");
    post_data = mapserver_read_post_data (r);
    szMethod  = MS_POST_REQUEST;
    if (strcmp (szContentType, "application/x-www-form-urlencoded") == 0) {
      argc = mapserver_decode_args (r->pool, (char*) apr_pstrdup (r->pool, r->args),
                                    &ParamNames, &ParamValues);
    }
  } else
    return HTTP_METHOD_NOT_ALLOWED;

  if (!argc && !post_data)
    return HTTP_BAD_REQUEST;

  /* Now we install the IO redirection.
  */
  if (msIO_installApacheRedirect (r) != MS_TRUE)
    ap_log_error (APLOG_MARK, APLOG_ERR, 0, NULL,
                  "%s: could not install apache redirect", __func__);


  mapserv = msAllocMapServObj();
  mapserv->request->NumParams   = argc;
  mapserv->request->ParamNames  = ParamNames;
  mapserv->request->ParamValues = ParamValues;
  mapserv->request->type        = (enum MS_REQUEST_TYPE) szMethod;
  mapserv->request->postrequest = post_data;
  mapserv->request->contenttype = szContentType;

  //mapserv->map = msModuleLoadMap(mapserv,conf);
  mapserv->map = conf->map;
  if(!mapserv->map) {
    msCGIWriteError(mapserv);
    goto end_request;
  }

  if(msCGIDispatchRequest(mapserv) != MS_SUCCESS) {
    msCGIWriteError(mapserv);
    goto end_request;
  }


end_request:
  if(mapserv) {
    msCGIWriteLog(mapserv,MS_FALSE);
    mapserv->request->ParamNames  = NULL;
    mapserv->request->ParamValues = NULL;
    mapserv->request->postrequest = NULL;
    mapserv->request->contenttype = NULL;
    mapserv->map = NULL;
    msFreeMapServObj(mapserv);
  }
  msResetErrorList();


  /* Check if status was set inside MapServer functions. If it was, we
   * return it's value instead of simply OK. This is to support redirects
   * from maptemplate.c
   */
  if (r->status == HTTP_MOVED_TEMPORARILY)
    return r->status;

  return OK;
}
Exemple #2
0
/**
 * @details This is called by `MapservAsync` and runs in a different thread to
 * that function.  It performs the actual work of interacting with
 * mapserver. The code is based on the logic found in the `mapserv` program but
 * the output is instead buffered using the mapserver output buffering
 * functionality: it can then be captured and passed back to the client.
 *
 * @param req The asynchronous libuv request.
 */
void Map::MapservWork(uv_work_t *req) {
  /* No HandleScope! This is run in a separate thread: *No* contact
     should be made with the Node/V8 world here. */

  MapBaton *baton = static_cast<MapBaton*>(req->data);
  mapservObj* mapserv = NULL;
  bool reportError = false;     // flag an error as worthy of reporting

  if (msDebugInitFromEnv() != MS_SUCCESS) {
    reportError = true;
    goto handle_error;
  }

  mapserv = msAllocMapServObj();

  msIO_installStdinFromBuffer(); // required to catch POSTS without data
  msIO_installStdoutToBuffer();  // required to capture mapserver output

  // load the CGI parameters from the environment object
  mapserv->request->NumParams = wrap_loadParams(mapserv->request,
                                                GetEnv,
                                                const_cast<char *>(baton->body.c_str()),
                                                baton->body.length(),
                                                static_cast<void *>(&(baton->env)));
  if( mapserv->request->NumParams == -1 ) {
    // no errors are generated by default but messages are output instead
    msSetError( MS_MISCERR, "No request parameters loaded",
                "Map::MapservWork" );
    reportError = true;
    goto get_output;
  }

  // Copy the map into the mapservObj for this request
  if(!LoadMap(mapserv, baton->map)) {
    reportError = true;
    goto get_output;
  }

  // Execute the request
  if(msCGIDispatchRequest(mapserv) != MS_SUCCESS) {
    reportError = true;
    goto get_output;
  }

 get_output:
  // Get the content type. If headers other than content-type need to be
  // retrieved it may be best to use something along the lines of
  // <https://github.com/joyent/http-parser>.
  baton->content_type = msIO_stripStdoutBufferContentType();
  msIO_stripStdoutBufferContentHeaders();
  
  // Get the buffered output
  baton->buffer = msIO_getStdoutBufferBytes();

 handle_error:
  // handle any unhandled errors
  errorObj *error = msGetErrorObj();
  if (error && error->code != MS_NOERR) {
    // report the error if requested
    if (reportError) {
      baton->error = new MapserverError(error);
    }
    msResetErrorList();         // clear all handled errors
  }

  // clean up
  msFreeMapServObj(mapserv);
  msIO_resetHandlers();
  msDebugCleanup();
  return;
}
Exemple #3
0
int main(int argc, char *argv[])
{
  int iArg;
  int sendheaders = MS_TRUE;
  struct mstimeval execstarttime, execendtime;
  struct mstimeval requeststarttime, requestendtime;
  mapservObj* mapserv = NULL;

  /* -------------------------------------------------------------------- */
  /*      Initialize mapserver.  This sets up threads, GD and GEOS as     */
  /*      well as using MS_ERRORFILE and MS_DEBUGLEVEL env vars if set.   */
  /* -------------------------------------------------------------------- */
  if( msSetup() != MS_SUCCESS ) {
    msCGIWriteError(mapserv);
    msCleanup(0);
    exit(0);
  }

  if(msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING)
    msGettimeofday(&execstarttime, NULL);

  /* -------------------------------------------------------------------- */
  /*      Process arguments.  In normal use as a cgi-bin there are no     */
  /*      commandline switches, but we provide a few for test/debug       */
  /*      purposes, and to query the version info.                        */
  /* -------------------------------------------------------------------- */
  for( iArg = 1; iArg < argc; iArg++ ) {
    /* Keep only "-v", "-nh" and "QUERY_STRING=..." enabled by default.
     * The others will require an explicit -DMS_ENABLE_CGI_CL_DEBUG_ARGS
     * at compile time.
     */
    if( strcmp(argv[iArg],"-v") == 0 ) {
      printf("%s\n", msGetVersion());
      fflush(stdout);
      exit(0);
    } else if(strcmp(argv[iArg], "-nh") == 0) {
      sendheaders = MS_FALSE;
    } else if( strncmp(argv[iArg], "QUERY_STRING=", 13) == 0 ) {
      /* Debugging hook... pass "QUERY_STRING=..." on the command-line */
      putenv( "REQUEST_METHOD=GET" );
      putenv( argv[iArg] );
    }
#ifdef MS_ENABLE_CGI_CL_DEBUG_ARGS
    else if( iArg < argc-1 && strcmp(argv[iArg], "-tmpbase") == 0) {
      msForceTmpFileBase( argv[++iArg] );
    } else if( iArg < argc-1 && strcmp(argv[iArg], "-t") == 0) {
      char **tokens;
      int numtokens=0;

      if((tokens=msTokenizeMap(argv[iArg+1], &numtokens)) != NULL) {
        int i;
        for(i=0; i<numtokens; i++)
          printf("%s\n", tokens[i]);
        msFreeCharArray(tokens, numtokens);
      } else {
        msCGIWriteError(mapserv);
      }

      exit(0);
    } else if( strncmp(argv[iArg], "MS_ERRORFILE=", 13) == 0 ) {
      msSetErrorFile( argv[iArg] + 13, NULL );
    } else if( strncmp(argv[iArg], "MS_DEBUGLEVEL=", 14) == 0) {
      msSetGlobalDebugLevel( atoi(argv[iArg] + 14) );
    }
#endif /* MS_ENABLE_CGI_CL_DEBUG_ARGS */
    else {
      /* we don't produce a usage message as some web servers pass junk arguments */
    }
  }

  /* -------------------------------------------------------------------- */
  /*      Setup cleanup magic, mainly for FastCGI case.                   */
  /* -------------------------------------------------------------------- */
#ifndef WIN32
  signal( SIGUSR1, msCleanupOnSignal );
  signal( SIGTERM, msCleanupOnSignal );
#endif

#ifdef USE_FASTCGI
  msIO_installFastCGIRedirect();

#ifdef WIN32
  atexit( msCleanupOnExit );
#endif

  /* In FastCGI case we loop accepting multiple requests.  In normal CGI */
  /* use we only accept and process one request.  */
  while( FCGI_Accept() >= 0 ) {
#endif /* def USE_FASTCGI */

    /* -------------------------------------------------------------------- */
    /*      Process a request.                                              */
    /* -------------------------------------------------------------------- */
    mapserv = msAllocMapServObj();
    mapserv->sendheaders = sendheaders; /* override the default if necessary (via command line -nh switch) */

    mapserv->request->NumParams = loadParams(mapserv->request, NULL, NULL, 0, NULL);
    if( mapserv->request->NumParams == -1 ) {
      msCGIWriteError(mapserv);
      goto end_request;
    }

    mapserv->map = msCGILoadMap(mapserv);
    if(!mapserv->map) {
      msCGIWriteError(mapserv);
      goto end_request;
    }

    if( mapserv->map->debug >= MS_DEBUGLEVEL_TUNING)
      msGettimeofday(&requeststarttime, NULL);

#ifdef USE_FASTCGI
    if( mapserv->map->debug ) {
      static int nRequestCounter = 1;

      msDebug( "CGI Request %d on process %d\n", nRequestCounter, getpid() );
      nRequestCounter++;
    }
#endif




    if(msCGIDispatchRequest(mapserv) != MS_SUCCESS) {
      msCGIWriteError(mapserv);
      goto end_request;
    }


end_request:
    if(mapserv) {
      if(mapserv->map && mapserv->map->debug >= MS_DEBUGLEVEL_TUNING) {
        msGettimeofday(&requestendtime, NULL);
        msDebug("mapserv request processing time (msLoadMap not incl.): %.3fs\n",
                (requestendtime.tv_sec+requestendtime.tv_usec/1.0e6)-
                (requeststarttime.tv_sec+requeststarttime.tv_usec/1.0e6) );
      }
      msCGIWriteLog(mapserv,MS_FALSE);
      msFreeMapServObj(mapserv);
    }
#ifdef USE_FASTCGI
    /* FCGI_ --- return to top of loop */
    msResetErrorList();
    continue;
  } /* end fastcgi loop */
#endif

  /* normal case, processing is complete */
  if(msGetGlobalDebugLevel() >= MS_DEBUGLEVEL_TUNING) {
    msGettimeofday(&execendtime, NULL);
    msDebug("mapserv total execution time: %.3fs\n",
            (execendtime.tv_sec+execendtime.tv_usec/1.0e6)-
            (execstarttime.tv_sec+execstarttime.tv_usec/1.0e6) );
  }
  msCleanup(0);

#ifdef _WIN32
  /* flush pending writes to stdout */
  fflush(stdout);
#endif

  exit( 0 );
}