int ec_responce_with_istag(ci_request_t * req, int ec) { char buf[256]; ci_service_xdata_t *srv_xdata; int len; srv_xdata = service_data(req->current_service_mod); ci_headers_reset(req->response_header); snprintf(buf, 256, "ICAP/1.0 %d %s", ci_error_code(ec), ci_error_code_string(ec)); ci_headers_add(req->response_header, buf); ci_headers_add(req->response_header, "Server: C-ICAP/" VERSION); if (req->keepalive) ci_headers_add(req->response_header, "Connection: keep-alive"); else ci_headers_add(req->response_header, "Connection: close"); ci_service_data_read_lock(srv_xdata); ci_headers_add(req->response_header, srv_xdata->ISTag); ci_service_data_read_unlock(srv_xdata); if (!ci_headers_is_empty(req->xheaders)) { ci_headers_addheaders(req->response_header, req->xheaders); } ci_headers_pack(req->response_header); len = ci_write(req->connection->fd, req->response_header->buf, req->response_header->bufused, TIMEOUT); if (len < 0) return -1; req->bytes_out += len; return len; }
int mk_responce_header(ci_request_t * req) { ci_headers_list_t *head; ci_encaps_entity_t **e_list; ci_service_xdata_t *srv_xdata; char buf[512]; srv_xdata = service_data(req->current_service_mod); ci_headers_reset(req->response_header); head = req->response_header; ci_headers_add(head, "ICAP/1.0 200 OK"); ci_headers_add(head, "Server: C-ICAP/" VERSION); if (req->keepalive) ci_headers_add(head, "Connection: keep-alive"); else ci_headers_add(head, "Connection: close"); ci_service_data_read_lock(srv_xdata); ci_headers_add(head, srv_xdata->ISTag); ci_service_data_read_unlock(srv_xdata); if (!ci_headers_is_empty(req->xheaders)) { ci_headers_addheaders(head, req->xheaders); } e_list = req->entities; if (req->type == ICAP_RESPMOD) { if (e_list[0]->type == ICAP_REQ_HDR) { ci_request_release_entity(req, 0); e_list[0] = e_list[1]; e_list[1] = e_list[2]; e_list[2] = NULL; } } snprintf(buf, 512, "Via: ICAP/1.0 %s (C-ICAP/" VERSION " %s )", MY_HOSTNAME, (req->current_service_mod->mod_short_descr ? req-> current_service_mod->mod_short_descr : req->current_service_mod-> mod_name)); buf[511] = '\0'; /*Here we must append it to an existsing Via header not just add a new header */ if (req->type == ICAP_RESPMOD) { ci_http_response_add_header(req, buf); } else if (req->type == ICAP_REQMOD) { ci_http_request_add_header(req, buf); } ci_response_pack(req); return 1; }
void options_responce(ci_request_t * req) { char buf[MAX_HEADER_SIZE + 1]; char *str; ci_headers_list_t *head; ci_service_xdata_t *srv_xdata; unsigned int xopts; int preview, allow204, max_conns, xlen; head = req->response_header; srv_xdata = service_data(req->current_service_mod); ci_headers_reset(head); ci_headers_add(head, "ICAP/1.0 200 OK"); strcpy(buf, "Methods: "); if (ci_method_support(req->current_service_mod->mod_type, ICAP_RESPMOD)) { strcat(buf, "RESPMOD"); if (ci_method_support (req->current_service_mod->mod_type, ICAP_REQMOD)) { strcat(buf, ", REQMOD"); } } else { /*At least one method must supported. A check for error must exists here..... */ strcat(buf, "REQMOD"); } ci_headers_add(head, buf); snprintf(buf, MAX_HEADER_SIZE, "Service: C-ICAP/" VERSION " server - %s", ((str = req->current_service_mod->mod_short_descr) ? str : req-> current_service_mod->mod_name)); buf[MAX_HEADER_SIZE] = '\0'; ci_headers_add(head, buf); ci_service_data_read_lock(srv_xdata); ci_headers_add(head, srv_xdata->ISTag); if (srv_xdata->TransferPreview[0] != '\0') ci_headers_add(head, srv_xdata->TransferPreview); if (srv_xdata->TransferIgnore[0] != '\0') ci_headers_add(head, srv_xdata->TransferIgnore); if (srv_xdata->TransferComplete[0] != '\0') ci_headers_add(head, srv_xdata->TransferComplete); /*Get service options before close the lock.... */ xopts = srv_xdata->xopts; preview = srv_xdata->preview_size; allow204 = srv_xdata->allow_204; max_conns = srv_xdata->max_connections; ci_service_data_read_unlock(srv_xdata); ci_debug_printf(5, "Options responce:\n" " Preview :%d\n" " Allow 204:%s\n" " TransferPreview:\"%s\"\n" " TransferIgnore:%s\n" " TransferComplete:%s\n" " Max-Connections:%d\n", preview,(allow204?"yes":"no"), srv_xdata->TransferPreview, srv_xdata->TransferIgnore, srv_xdata->TransferComplete, max_conns ); /* ci_headers_add(head, "Max-Connections: 20"); */ ci_headers_add(head, "Options-TTL: 3600"); strcpy(buf, "Date: "); ci_strtime_rfc822(buf + strlen(buf)); ci_headers_add(head, buf); if (preview >= 0) { sprintf(buf, "Preview: %d", srv_xdata->preview_size); ci_headers_add(head, buf); } if(max_conns > 0) { sprintf(buf, "Max-Connections: %d", max_conns); ci_headers_add(head, buf); } if (allow204) { ci_headers_add(head, "Allow: 204"); } if (xopts) { strcpy(buf, "X-Include: "); xlen = 11; /*sizeof("X-Include: ") */ if ((xopts & CI_XCLIENTIP)) { strcat(buf, "X-Client-IP"); xlen += sizeof("X-Client-IP"); } if ((xopts & CI_XSERVERIP)) { if (xlen > 11) { strcat(buf, ", "); xlen += 2; } strcat(buf, "X-Server-IP"); xlen += sizeof("X-Server-IP"); } if ((xopts & CI_XSUBSCRIBERID)) { if (xlen > 11) { strcat(buf, ", "); xlen += 2; } strcat(buf, "X-Subscriber-ID"); xlen += sizeof("X-Subscriber-ID"); } if ((xopts & CI_XAUTHENTICATEDUSER)) { if (xlen > 11) { strcat(buf, ", "); xlen += 2; } strcat(buf, "X-Authenticated-User"); xlen += sizeof("X-Authenticated-User"); } if ((xopts & CI_XAUTHENTICATEDGROUPS)) { if (xlen > 11) { strcat(buf, ", "); xlen += 2; } strcat(buf, "X-Authenticated-Groups"); xlen += sizeof("X-Authenticated-Groups"); } if (xlen > 11) ci_headers_add(head, buf); } ci_response_pack(req); req->pstrblock_responce = head->buf; req->remain_send_block_bytes = head->bufused; do { if ((ci_wait_for_data(req->connection->fd, TIMEOUT, wait_for_write)) <= 0) { ci_debug_printf(3, "Timeout sending data. Ending .......\n"); return; } if (send_current_block_data(req) == CI_ERROR) { ci_debug_printf(3, "Error sending data. Ending .....\n"); return; } } while (req->remain_send_block_bytes > 0); // if(responce_body) // send_body_responce(req,responce_body); }
int process_request(ci_request_t * req) { int res; ci_service_xdata_t *srv_xdata; res = do_request(req); if (!STATS) return res; if (res<0 && req->request_header->bufused == 0) /*Did not read anything*/ return res; if (req->return_code == EC_404) { return res; } srv_xdata = service_data(req->current_service_mod); if (!srv_xdata) { ci_debug_printf(5, "Service not found, statistics not logged."); return res; } STATS_LOCK(); if (STAT_REQUESTS >= 0) STATS_INT64_INC(STAT_REQUESTS,1); if (req->type == ICAP_REQMOD) { STATS_INT64_INC(STAT_REQMODS, 1); STATS_INT64_INC(srv_xdata->stat_reqmods, 1); } else if (req->type == ICAP_RESPMOD) { STATS_INT64_INC(STAT_RESPMODS, 1); STATS_INT64_INC(srv_xdata->stat_respmods, 1); } else if (req->type == ICAP_OPTIONS) { STATS_INT64_INC(STAT_OPTIONS, 1); STATS_INT64_INC(srv_xdata->stat_options, 1); } if (res <0 && STAT_FAILED_REQUESTS >= 0) STATS_INT64_INC(STAT_FAILED_REQUESTS,1); if (req->return_code == EC_204) { STATS_INT64_INC(STAT_ALLOW204, 1); STATS_INT64_INC(srv_xdata->stat_allow204, 1); } if (STAT_BYTES_IN >= 0) STATS_KBS_INC(STAT_BYTES_IN, req->bytes_in); if (STAT_BYTES_OUT >= 0) STATS_KBS_INC(STAT_BYTES_OUT, req->bytes_out); if (STAT_HTTP_BYTES_IN >= 0) STATS_KBS_INC(STAT_HTTP_BYTES_IN, req->http_bytes_in); if (STAT_HTTP_BYTES_OUT >= 0) STATS_KBS_INC(STAT_HTTP_BYTES_OUT, req->http_bytes_out); if (STAT_BODY_BYTES_IN >= 0) STATS_KBS_INC(STAT_BODY_BYTES_IN, req->body_bytes_in); if (STAT_BODY_BYTES_OUT >= 0) STATS_KBS_INC(STAT_BODY_BYTES_OUT, req->body_bytes_out); if (srv_xdata->stat_bytes_in >= 0) STATS_KBS_INC(srv_xdata->stat_bytes_in, req->bytes_in); if (srv_xdata->stat_bytes_out >= 0) STATS_KBS_INC(srv_xdata->stat_bytes_out, req->bytes_out); if (srv_xdata->stat_http_bytes_in >= 0) STATS_KBS_INC(srv_xdata->stat_http_bytes_in, req->http_bytes_in); if (srv_xdata->stat_http_bytes_out >= 0) STATS_KBS_INC(srv_xdata->stat_http_bytes_out, req->http_bytes_out); if (srv_xdata->stat_body_bytes_in >= 0) STATS_KBS_INC(srv_xdata->stat_body_bytes_in, req->body_bytes_in); if (srv_xdata->stat_body_bytes_out >= 0) STATS_KBS_INC(srv_xdata->stat_body_bytes_out, req->body_bytes_out); STATS_UNLOCK(); return res; }
/********************** Service aliases *****************************/ service_alias_t *add_service_alias(char *service_alias, char *service_name, char *args) { ci_service_module_t *service = NULL; service_alias_t *salias = NULL; ci_service_xdata_t *xdata = NULL; int len = 0; int alias_indx = 0; if (service_aliases == NULL) { service_aliases = malloc(STEP * sizeof(service_alias_t)); service_aliases_size = STEP; } else if (service_aliases_num == service_aliases_size) { service_aliases_size += STEP; service_aliases = realloc(service_aliases, service_aliases_size * sizeof(service_alias_t)); } if (service_aliases == NULL) { ci_debug_printf(1, "add_service_alias: Error allocating memory. Exiting...\n"); exit(-1); } service = find_service(service_name); if (!service) { salias = find_service_alias(service_name); if (!salias) return NULL; service = salias->service; } xdata = service_data(service); alias_indx = service_aliases_num; service_aliases_num++; service_aliases[alias_indx].service = service; strncpy(service_aliases[alias_indx].alias, service_alias, MAX_SERVICE_NAME); service_aliases[alias_indx].alias[MAX_SERVICE_NAME] = '\0'; service_aliases[alias_indx].args[0] = '\0'; if (salias) { len = strlen(salias->args); strcpy(service_aliases[alias_indx].args, salias->args); /*we had check for len */ } if (args && len) { service_aliases[alias_indx].args[len] = '&'; len++; } if (args && MAX_SERVICE_ARGS - len > 0) { strcpy(service_aliases[alias_indx].args + len, args); } service_aliases[alias_indx].args[MAX_SERVICE_ARGS] = '\0'; if (xdata->intl_srv_conf_table) register_conf_table(service_aliases[alias_indx].alias, xdata->intl_srv_conf_table, ALIAS_TABLE); return &(service_aliases[alias_indx]); }
void configuration_t::parse_services_settings(const Json::Value& config_value) { const Json::Value services_list = config_value["services"]; if (!services_list.isObject() || !services_list.size()) { std::string error_str = "\"services\" section is malformed, it must have at least one service defined, "; error_str += "see documentation for more info."; throw internal_error(error_str); } Json::Value::Members services_names(services_list.getMemberNames()); for (Json::Value::Members::iterator it = services_names.begin(); it != services_names.end(); ++it) { std::string service_name(*it); Json::Value service_data(services_list[service_name]); if (!service_data.isObject()) { std::string error_str = "\"service\" (with alias: " + service_name + ") is malformed, "; error_str += "see documentation for more info."; throw internal_error(error_str); } service_info_t si; si.name = service_name; boost::trim(si.name); if (si.name.empty()) { std::string error_str = "malformed \"service\" section found, alias must me non-empty string"; throw internal_error(error_str); } si.description = service_data.get("description", "").asString(); boost::trim(si.description); si.app = service_data.get("app", "").asString(); boost::trim(si.app); if (si.app.empty()) { std::string error_str = "malformed \"service\" " + si.name + " section found, field"; error_str += "\"app\" must me non-empty string"; throw internal_error(error_str); } // cocaine nodes autodiscovery const Json::Value autodiscovery = service_data["autodiscovery"]; if (!autodiscovery.isObject()) { std::string error_str = "\"autodiscovery\" section for service " + service_name + " is malformed, "; error_str += "see documentation for more info."; throw internal_error(error_str); } si.hosts_source = autodiscovery.get("source", "").asString(); boost::trim(si.hosts_source); if (si.hosts_source.empty()) { std::string error_str = "malformed \"service\" " + si.name + " section found, field"; error_str += "\"source\" must me non-empty string"; throw internal_error(error_str); } char* absolute_source_path = realpath(si.hosts_source.c_str(), NULL); if (NULL != absolute_source_path) { si.hosts_source = absolute_source_path; } std::string autodiscovery_type_str = autodiscovery.get("type", "").asString(); if (autodiscovery_type_str == "FILE") { si.discovery_type = AT_FILE; } else if (autodiscovery_type_str == "HTTP") { si.discovery_type = AT_HTTP; } else if (autodiscovery_type_str == "MULTICAST") { si.discovery_type = AT_MULTICAST; } else { std::string error_str = "\"autodiscovery\" section for service " + service_name; error_str += " has malformed field \"type\", which can only take values FILE, HTTP, MULTICAST."; throw internal_error(error_str); } // default message policy const Json::Value mpolicy = service_data["policy"]; if (mpolicy.isObject()) { si.policy.urgent = mpolicy.get("urgent", defaults_t::policy_urgent).asBool(); si.policy.persistent = mpolicy.get("persistent", defaults_t::policy_persistent).asBool(); si.policy.timeout = mpolicy.get("timeout", defaults_t::policy_chunk_timeout).asFloat(); si.policy.ack_timeout = mpolicy.get("ack_timeout", defaults_t::policy_ack_timeout).asFloat(); si.policy.deadline = mpolicy.get("deadline", defaults_t::policy_message_deadline).asFloat(); si.policy.max_retries = mpolicy.get("max_retries", defaults_t::policy_max_retries).asInt(); } // check for duplicate services std::map<std::string, service_info_t>::iterator lit = m_services_list.begin(); for (;lit != m_services_list.end(); ++lit) { if (lit->second.name == si.name) { throw internal_error("duplicate service with name " + si.name + " was found in config!"); } } m_services_list[si.name] = si; } }