📄 mod_gsoap.c
字号:
static int gsoap_header_parser(request_rec *r);static bool AddSharedLibrary(gsoapConfiguration *pConfig, const char *pszPath, const bool bIsSOAPLibrary);/*--------------------------------------------------------------------------*//* *//* Data declarations. *//* *//* Here are the static cells and structure declarations private to our *//* module. *//* *//*--------------------------------------------------------------------------*///empty/*--------------------------------------------------------------------------*//* We prototyped the various syntax for command handlers (routines that *//* are called when the configuration parser detects a directive declared *//* by our module) earlier. Now we actually declare a "real" routine that *//* will be invoked by the parser when our "real" directive is *//* encountered. *//* *//* If a command handler encounters a problem processing the directive, it *//* signals this fact by returning a non-NULL pointer to a string *//* describing the problem. *//* *//* The magic return value DECLINE_CMD is used to deal with directives *//* that might be declared by multiple modules. If the command handler *//* returns NULL, the directive was processed; if it returns DECLINE_CMD, *//* the next module (if any) that declares the directive is given a chance *//* at it. If it returns any other value, it's treated as the text of an *//* error message. *//*--------------------------------------------------------------------------*//** Command handler for the TAKE1 "SOAPLibrary" directive. * We remember the load path for the shared library that contains the SOAP server. */static const char *cmd_SoapLibrary(cmd_parms *cmd, void *mconfig, const char *pszPath) { gsoapConfiguration *pConfig = (gsoapConfiguration *)mconfig; AddSharedLibrary(pConfig, pszPath, true); return NULL;}/** Command handler for the TAKE1 "SOAPSupportLibrary" directive. * We remember the load path for a shared library that must additionally loaded. * This is a mechanism to load libraries that the SOAPLibrary depends on. * This type of libraries do not contain our soap server. */static const char *cmd_SupportLibrary(cmd_parms *cmd, void *mconfig, const char *pszPath) { gsoapConfiguration *pConfig = (gsoapConfiguration *)mconfig; AddSharedLibrary(pConfig, pszPath, false); return NULL;}typedef const char *(*command_function_interface)();/** List of directives specific to our module. */static const command_rec gsoap_cmds[] = { { "SOAPLibrary", ///< directive name (command_function_interface)cmd_SoapLibrary, ///< config action routine NULL, ///< argument to include in call ACCESS_CONF, ///< where available TAKE1, ///< arguments "SOAP shared Library that will be dynamically loaded. - 1 argument (path)" ///< directive description }, { "SupportLibrary", ///< directive name (command_function_interface)cmd_SupportLibrary, ///< config action routine NULL, ///< argument to include in call ACCESS_CONF, ///< where available TAKE1, ///< arguments "additional library that must be dynamically loaded - 1 argument (path)" ///< directive description }, {NULL}};/*--------------------------------------------------------------------------*//* *//* Now the list of content handlers available from this module. *//* *//*--------------------------------------------------------------------------*//* * List of content handlers our module supplies. Each handler is defined by * two parts: a name by which it can be referenced (such as by * {Add,Set}Handler), and the actual routine name. The list is terminated by * a NULL block, since it can be of variable length. * * Note that content-handlers are invoked on a most-specific to least-specific * basis; that is, a handler that is declared for "text/plain" will be * invoked before one that was declared for "text / *". Note also that * if a content-handler returns anything except DECLINED, no other * content-handlers will be called. */static const handler_rec gsoap_handlers[] ={ {"gsoap-handler", gsoap_handler}, {NULL}};/*--------------------------------------------------------------------------*//* *//* All of the routines have been declared now. Here's the list of *//* directives specific to our module, and information about where they *//* may appear and how the command parser should pass them to us for *//* processing. Note that care must be taken to ensure that there are NO *//* collisions of directive names between modules. *//* *//*--------------------------------------------------------------------------*//* * Module definition for configuration. If a particular callback is not * needed, replace its routine name below with the word NULL. * * The number in brackets indicates the order in which the routine is called * during request processing. Note that not all routines are necessarily * called (such as if a resource doesn't have access restrictions). *//** List of callback routines and data structures that provide the hooks into our module. */module MODULE_VAR_EXPORT gsoap_module ={ STANDARD_MODULE_STUFF, gsoap_init, /* module initializer */ gsoap_create_dir_config, /* per-directory config creator */ gsoap_merge_dir_config, /* dir config merger */ gsoap_create_server_config, /* server config creator */ gsoap_merge_server_config, /* server config merger */ gsoap_cmds, /* command table */ gsoap_handlers, /* [9] list of handlers */ gsoap_translate_handler, /* [2] filename-to-URI translation */ gsoap_check_user_id, /* [5] check/validate user_id */ gsoap_auth_checker, /* [6] check user_id is valid *here* */ gsoap_access_checker, /* [4] check access by host address */ gsoap_type_checker, /* [7] MIME type checker/setter */ gsoap_fixer_upper, /* [8] fixups */ gsoap_logger, /* [10] logger */ gsoap_header_parser, /* [3] header parser */ gsoap_child_init, /* process initializer */ gsoap_child_exit, /* process exit/cleanup */ gsoap_post_read_request /* [1] post read_request handling */};/** helper to write out the headers */static int ListHeadersCallback(void *rec, const char *key, const char *value) { request_rec *r = (request_rec *)rec; ap_rprintf(r, "%s: %s<br>", key, value); return 1;}/** write out the headers of the request. */static void ListHeaders(request_rec *r) { ap_table_do(ListHeadersCallback, r, r->headers_in, NULL);}/** send the error message to the client browser */static void SendErrorMessage(request_rec *r, const char *pszError) { gsoapConfiguration *pConfig = getConfiguration(r); ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "mod_gsoap: %s", pszError, NULL); r->content_type = "text/html"; ap_send_http_header(r); ap_rputs(DOCTYPE_HTML_3_2, r); ap_rputs("<HTML>\n", r); ap_rputs(" <HEAD>\n", r); ap_rputs(" <TITLE>Apache Soap Handler\n", r); ap_rputs(" </TITLE>\n", r); ap_rputs(" </HEAD>\n", r); ap_rputs(" <BODY>\n", r); ap_rputs(" <H1>mod_gsoap Apache SOAP Server Error</H1>\n", r); ap_rprintf(r, "<p><strong>%s</strong><br>Please see the documentation at <a href=\"http://www.webware.at/SOAP\">WebWare</a> for details.</p>", pszError); ap_rputs(" <H2>Content headers of the request</H2>\n", r); ListHeaders(r); ap_rputs("</BODY></HTML>\n", r);}static int send_header_to_gsoap(void *pvoid, const char *key, const char *value) { gsoapRequestConfiguration *pRqConf = NULL; struct soap *psoap = (struct soap *)pvoid; if (NULL != psoap) { pRqConf = getRequestConfiguration(psoap); } if (NULL == pRqConf) { return 0; } if (0 == strcasecmp(key, "SOAPAction") || 0 == strcasecmp(key, "Content-Type") || 0 == strcasecmp(key, "Status") || 0 == strcasecmp(key, "Content-Length")) { psoap->fparsehdr(psoap, key, value); } return 1;}/* Callback functions for gsoap. We must parse the headers ourselves and * we must handle send/receive properly. */static int http_post_header(struct soap *soap, const char *key, const char *value) { gsoapRequestConfiguration *pRqConf = getRequestConfiguration(soap); request_rec *r = NULL == pRqConf ? NULL : pRqConf->r; if (NULL != value) { if (0 == strcasecmp(key, "SOAPAction")) { ap_table_set(r->headers_out, key, value); } else if (0 == strcasecmp(key, "Content-Type")) { r->content_type = ap_pstrdup(r->pool, value); } else if (0 == strcasecmp(key, "Content-Length")) { ap_set_content_length(r, atoi(value)); } } return SOAP_OK;}/** gsoap function that requests the next piece of data from us */static size_t frecv(struct soap *psoap, char *pBuf, size_t len) { request_rec *r = NULL; int nRet = 0; gsoapRequestConfiguration *pRqConf = getRequestConfiguration(psoap); if (NULL != pRqConf) { r = pRqConf->r; if (!pRqConf->headers_received) { ap_table_do(send_header_to_gsoap, psoap, r->headers_in, NULL); pRqConf->headers_received = true; } if (r->remaining > 0) { nRet = ap_get_client_block(r, pBuf, len > r->remaining ? r->remaining : len); } } return nRet;}static int fsend(struct soap *psoap, const char *pBuf, size_t len) { int nWritten = 0; int nRet = SOAP_OK; gsoapRequestConfiguration *pRqConf = getRequestConfiguration(psoap); if (NULL != pRqConf) { request_rec *r = pRqConf->r; if (!pRqConf->headers_sent) { ap_send_http_header(r); pRqConf->headers_sent = true; } nRet = ap_rwrite(pBuf, len, r) == len ? SOAP_OK : SOAP_FAULT; } else { nRet = SOAP_FAULT; } return nRet;}/** instead of real header parsing we skip that. */static int http_parse(struct soap *psoap) { return SOAP_OK;}/* plugin functions */static int mod_gsoap_plugin_copy(struct soap *soap, struct soap_plugin *dst, struct soap_plugin *src) { *dst = *src;}static void mod_gsoap_delete(struct soap *soap, struct soap_plugin *p) {}static int mod_gsoap_plugin(struct soap *soap, struct soap_plugin *p, void *arg) { p->id = GSOAP_ID; p->data = arg; p->fcopy = mod_gsoap_plugin_copy; p->fdelete = mod_gsoap_delete; return SOAP_OK;} static void set_callbacks(request_rec *r, gsoapRequestConfiguration *pRqConf, struct soap *psoap) { gsoapConfiguration *pConfig = getConfiguration(r); struct apache_soap_interface *pIntf = pConfig->m_pLibraries->m_pIntf; pRqConf->r = r; pRqConf->http_parse = psoap->fparse;// psoap->user = pRqConf; psoap->frecv = frecv; psoap->fsend = fsend; psoap->fparse = http_parse; psoap->fposthdr = http_post_header; if (NULL != pIntf->fsoap_init) { (*pIntf->fsoap_register_plugin_arg)(psoap, mod_gsoap_plugin, (void *)pRqConf); } else { //psoap->user = pRqConf }}/*--------------------------------------------------------------------------*//* *//* Now we declare our content handlers, which are invoked when the server *//* encounters a document which our module is supposed to have a chance to *//* see. (See mod_mime's SetHandler and AddHandler directives, and the *//* mod_info and mod_status examples, for more details.) *//* *//* Since content handlers are dumping data directly into the connexion *//* (using the r*() routines, such as rputs() and rprintf()) without *//* intervention by other parts of the server, they need to make *//* sure any accumulated HTTP headers are sent first. This is done by *//* calling send_http_header(). Otherwise, no header will be sent at all, *//* and the output sent to the client will actually be HTTP-uncompliant. *//*--------------------------------------------------------------------------*//** * SOAP content handler. * * @return the value that instructs the caller concerning what happened and what to do next. * OK ("we did our thing") * DECLINED ("this isn't something with which we want to get involved") * HTTP_mumble ("an error status should be reported") */static int gsoap_handler(request_rec *r) { static const int nResponseBufferLen = IOBUF_CHUNK_SIZE; const char *pszError = NULL; struct soap *psoap = NULL; struct apache_soap_interface *pIntf = NULL; int nContentLength = 0; int nRet = 0; int nWritten = 0, nRead = 0; char *pszResponse = ap_pcalloc(r->pool, nResponseBufferLen); gsoapConfiguration *pConfig = getConfiguration(r); gsoapRequestConfiguration *pRqConf = NULL; assert(NULL != pConfig); psoap = (struct soap *)ap_pcalloc(r->pool, sizeof(struct soap)); pRqConf = ap_pcalloc(r->pool, sizeof(gsoapRequestConfiguration)); pszError = SoapSharedLibraries_loadAllLibraries(pConfig->m_pLibraries, r->pool); pIntf = pConfig->m_pLibraries->m_pIntf; ap_update_mtime(r, r->request_time); ap_set_last_modified(r); if (NULL != pszError) { static bool bFirstTime = true; if (bFirstTime) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, pszError); bFirstTime = false; } } if (NULL == pszError) { if (0 != strcmp(r->method, "POST")) { pszError = "Only POST allowed as request for SOAP!"; } } /* as a next step, we prepare a buffer that sends the request as first line to gsoap. * Then the remaining data. * We start returning bytes on frecv from this buffer, until it is empty. * then it is not necessary to fiddle around with gsoap's request line parsing. */ if (NULL == pszError) { pRqConf->r = r; pRqConf->headers_sent = false; pRqConf->headers_received = false; pRqConf->m_pszAllHeaders = NULL; pRqConf->m_nHeaderLength = strlen(r->the_request) + 2; pRqConf->m_pszCurrentHeaderReadingPosition = NULL; pRqConf->m_nOutBufCount = 0; pRqConf->m_nOutBufLength = nResponseBufferLen; pRqConf->m_pOutBuf = ap_pcalloc(r->pool, nResponseBufferLen); pRqConf->http_parse = NULL; pRqConf->m_pszAllHeaders = ap_pcalloc(r->pool, pRqConf->m_nHeaderLength + 1); pRqConf->m_pszCurrentHeaderReadingPosition = pRqConf->m_pszAllHeaders; strcpy(pRqConf->m_pszAllHeaders, r->the_request); strcat(pRqConf->m_pszAllHeaders, "\r\n"); } /* * We're about to start sending content, so we need to force the HTTP * headers to be sent at this point. Otherwise, no headers will be sent * at all. We can set any we like first, of course. **NOTE** Here's * where you set the "Content-type" header, and you do so by putting it in * r->content_type, *not* r->headers_out("Content-type"). If you don't * set it, it will be filled in with the server's default type (typically * "text/plain"). You *must* also ensure that r->content_type is lower
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -