TEST(Utils, UriCoding) { string src1 = "This is a simple & short test."; string src2 = "$ & < > ? ; # : = , \" ' ~ + %-_"; string src3 = "! * ' ( ) ; : @ & = + $ , / ? % # [ ]"; string src4 = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i " "j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 - _ . ~"; string dst1 = "This%20is%20a%20simple%20%26%20short%20test."; string dst2 = "%24%20%26%20%3C%20%3E%20%3F%20%3B%20%23%20%3A%20%3D%20%2C%20%22%20%27%" "20~%20%2B%20%25-_"; string dst3 = "%21%20%2A%20%27%20%28%20%29%20%3B%20%3A%20%40%20%26%20%3D%20%2B%20%24%" "20%2C%20%2F%20%3F%20%25%20%23%20%5B%20%5D"; string dst4 = "A%20B%20C%20D%20E%20F%20G%20H%20I%20J%20K%20L%20M%20N%20O%20P%20Q%20R%" "20S%20T%20U%20V%20W%20X%20Y%20Z%20a%20b%20c%20d%20e%20f%20g%20h%20i%" "20j%20k%20l%20m%20n%20o%20p%20q%20r%20s%20t%20u%20v%20w%20x%20y%20z%" "200%201%202%203%204%205%206%207%208%209%20-%20_%20.%20~"; EXPECT_STREQ(dst1.c_str(), uri_encode(src1).c_str()); EXPECT_STREQ(dst2.c_str(), uri_encode(src2).c_str()); EXPECT_STREQ(dst3.c_str(), uri_encode(src3).c_str()); EXPECT_STREQ(dst4.c_str(), uri_encode(src4).c_str()); EXPECT_STREQ(src1.c_str(), uri_decode(dst1).c_str()); EXPECT_STREQ(src2.c_str(), uri_decode(dst2).c_str()); EXPECT_STREQ(src3.c_str(), uri_decode(dst3).c_str()); EXPECT_STREQ(src4.c_str(), uri_decode(dst4).c_str()); }
/** * Build OCSP URI string * * @v ocsp OCSP check * @ret rc Return status code */ static int ocsp_uri_string ( struct ocsp_check *ocsp ) { struct x509_ocsp_responder *responder = &ocsp->cert->extensions.auth_info.ocsp; char *base64; char *sep; size_t base64_len; size_t uri_len; size_t len; int rc; /* Sanity check */ if ( ! responder->uri.len ) { DBGC ( ocsp, "OCSP %p \"%s\" has no OCSP URI\n", ocsp, x509_name ( ocsp->cert ) ); rc = -ENOTTY; goto err_no_uri; } /* Calculate base64-encoded request length */ base64_len = ( base64_encoded_len ( ocsp->request.builder.len ) + 1 /* NUL */ ); /* Allocate and construct the base64-encoded request */ base64 = malloc ( base64_len ); if ( ! base64 ) { rc = -ENOMEM; goto err_alloc_base64; } base64_encode ( ocsp->request.builder.data, ocsp->request.builder.len, base64, base64_len ); /* Calculate URI-encoded base64-encoded request length */ uri_len = ( uri_encode ( URI_PATH, base64, ( base64_len - 1 /* NUL */ ), NULL, 0 ) + 1 /* NUL */ ); /* Allocate and construct the URI string */ len = ( responder->uri.len + 1 /* possible "/" */ + uri_len ); ocsp->uri_string = zalloc ( len ); if ( ! ocsp->uri_string ) { rc = -ENOMEM; goto err_alloc_uri; } memcpy ( ocsp->uri_string, responder->uri.data, responder->uri.len ); sep = &ocsp->uri_string[ responder->uri.len - 1 ]; if ( *sep != '/' ) *(++sep) = '/'; uri_encode ( URI_PATH, base64, base64_len, ( sep + 1 ), uri_len ); DBGC2 ( ocsp, "OCSP %p \"%s\" URI is %s\n", ocsp, x509_name ( ocsp->cert ), ocsp->uri_string ); /* Success */ rc = 0; err_alloc_uri: free ( base64 ); err_alloc_base64: err_no_uri: return rc; }
/** * Unparse URI * * @v buf Buffer to fill with URI string * @v size Size of buffer * @v uri URI to write into buffer, or NULL * @v fields Bitmask of fields to include in URI string, or URI_ALL * @ret len Length of URI string */ int unparse_uri ( char *buf, size_t size, struct uri *uri, unsigned int fields ) { /* List of characters that typically go before certain fields */ static char separators[] = { /* scheme */ 0, /* opaque */ ':', /* user */ 0, /* password */ ':', /* host */ '@', /* port */ ':', /* path */ 0, /* query */ '?', /* fragment */ '#' }; int used = 0; int i; DBG ( "URI unparsing" ); dump_uri ( uri ); DBG ( "\n" ); /* Ensure buffer is NUL-terminated */ if ( size ) buf[0] = '\0'; /* Special-case NULL URI */ if ( ! uri ) return 0; /* Iterate through requested fields */ for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) { const char *field = uri_get_field ( uri, i ); char sep = separators[i]; /* Ensure `fields' only contains bits for fields that exist */ if ( ! field ) fields &= ~( 1 << i ); /* Store this field if we were asked to */ if ( fields & ( 1 << i ) ) { /* Print :// if we're non-opaque and had a scheme */ if ( ( fields & URI_SCHEME_BIT ) && ( i > URI_OPAQUE ) ) { used += ssnprintf ( buf + used, size - used, "://" ); /* Only print :// once */ fields &= ~URI_SCHEME_BIT; } /* Only print separator if an earlier field exists */ if ( sep && ( fields & ( ( 1 << i ) - 1 ) ) ) used += ssnprintf ( buf + used, size - used, "%c", sep ); /* Print contents of field, possibly encoded */ if ( URI_ENCODED & ( 1 << i ) ) used += uri_encode ( field, buf + used, size - used, i ); else used += ssnprintf ( buf + used, size - used, "%s", field ); } } return used; }
/** * Format URI * * @v uri URI * @v buf Buffer to fill with URI string * @v size Size of buffer * @ret len Length of URI string */ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) { static const char prefixes[URI_FIELDS] = { [URI_OPAQUE] = ':', [URI_PASSWORD] = ':', [URI_PORT] = ':', [URI_PATH] = '/', [URI_QUERY] = '?', [URI_FRAGMENT] = '#', }; char prefix; size_t used = 0; unsigned int field; /* Ensure buffer is NUL-terminated */ if ( len ) buf[0] = '\0'; /* Special-case NULL URI */ if ( ! uri ) return 0; /* Generate fields */ for ( field = 0 ; field < URI_FIELDS ; field++ ) { /* Skip non-existent fields */ if ( ! uri_field ( uri, field ) ) continue; /* Prefix this field, if applicable */ prefix = prefixes[field]; if ( ( field == URI_HOST ) && ( uri->user != NULL ) ) prefix = '@'; if ( ( field == URI_PATH ) && ( uri->path[0] == '/' ) ) prefix = '\0'; if ( prefix ) { used += ssnprintf ( ( buf + used ), ( len - used ), "%c", prefix ); } /* Encode this field */ used += uri_encode ( uri_field ( uri, field ), field, ( buf + used ), ( len - used ) ); /* Suffix this field, if applicable */ if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) { used += ssnprintf ( ( buf + used ), ( len - used ), "://" ); } } if ( len ) { DBGC ( uri, "URI formatted" ); uri_dump ( uri ); DBGC ( uri, " to \"%s%s\"\n", buf, ( ( used > len ) ? "<TRUNCATED>" : "" ) ); } return used; }
S3Params S3BucketReader::constructReaderParams(BucketContent& key) { S3Params readerParams = this->params; // encode the key name but leave the "/" // "/encoded_path/encoded_name" string keyEncoded = uri_encode(key.getName()); find_replace(keyEncoded, "%2F", "/"); readerParams.setKeyUrl(this->getKeyURL(keyEncoded)); readerParams.setRegion(this->region); readerParams.setKeySize(key.getSize()); S3DEBUG("key: %s, size: %" PRIu64, readerParams.getKeyUrl().c_str(), readerParams.getKeySize()); return readerParams; }
std::string srv_debug(const Ctracker_input& ti) { std::ostringstream os; os << "<!DOCTYPE HTML><meta http-equiv=refresh content=60><title>XBT Tracker</title>"; os << "<table>"; if (ti.m_info_hash.empty()) { for (auto& i : m_torrents) { if (!i.second.leechers && !i.second.seeders) continue; os << "<tr><td class=ar>" << i.second.fid << "<td><a href=\"?info_hash=" << uri_encode(i.first) << "\">" << hex_encode(i.first) << "</a>" << "<td>" << (i.second.dirty ? '*' : ' ') << "<td class=ar>" << i.second.leechers << "<td class=ar>" << i.second.seeders; } } else if (const t_torrent* i = find_torrent(ti.m_info_hash)) debug(*i, os); os << "</table>"; return os.str(); }
void Cconnection::read(const std::string& v) { #ifndef NDEBUG std::cout << v << std::endl; #endif if (srv_config().m_log_access) { static std::ofstream f("xbt_tracker_raw.log"); f << srv_time() << '\t' << inet_ntoa(m_a.sin_addr) << '\t' << ntohs(m_a.sin_port) << '\t' << v << std::endl; } Ctracker_input ti; size_t e = v.find('?'); if (e == std::string::npos) e = v.size(); else { size_t a = e + 1; size_t b = v.find(' ', a); if (b == std::string::npos) return; while (a < b) { size_t c = v.find('=', a); if (c++ == std::string::npos) break; size_t d = v.find_first_of(" &", c); if (d == std::string::npos) break; ti.set(v.substr(a, c - a - 1), uri_decode(v.substr(c, d - c))); a = d + 1; } } if (!ti.m_ipa || !is_private_ipa(m_a.sin_addr.s_addr)) ti.m_ipa = m_a.sin_addr.s_addr; str_ref torrent_pass; size_t a = 4; if (a < e && v[a] == '/') { a++; if (a + 32 < e && v[a + 32] == '/') { torrent_pass.assign(&v[a], 32); a += 33; } } std::string h = "HTTP/1.0 200 OK\r\n"; std::string s; bool gzip = true; switch (a < v.size() ? v[a] : 0) { case 'a': if (ti.valid()) { gzip = false; std::string error = srv_insert_peer(ti, false, find_user_by_torrent_pass(torrent_pass, ti.m_info_hash)); s = error.empty() ? srv_select_peers(ti) : (boost::format("d14:failure reason%d:%se") % error.size() % error).str(); } break; case 'd': if (srv_config().m_debug) { h += "Content-Type: text/html; charset=us-ascii\r\n"; s = srv_debug(ti); } break; case 's': if (v.size() >= 7 && v[6] == 't') { h += "Content-Type: text/html; charset=us-ascii\r\n"; s = srv_statistics(); } else if (srv_config().m_full_scrape || !ti.m_info_hash.empty()) { gzip = srv_config().m_gzip_scrape && ti.m_info_hash.empty(); s = srv_scrape(ti, find_user_by_torrent_pass(torrent_pass, ti.m_info_hash)); } break; } if (s.empty()) { if (!ti.m_info_hash.empty() || srv_config().m_redirect_url.empty()) h = "HTTP/1.0 404 Not Found\r\n"; else { h = "HTTP/1.0 302 Found\r\n" "Location: " + srv_config().m_redirect_url + (ti.m_info_hash.empty() ? "" : "?info_hash=" + uri_encode(ti.m_info_hash)) + "\r\n"; } } else if (gzip) { shared_data s2 = xcc_z::gzip(s); #ifndef NDEBUG static std::ofstream f("xbt_tracker_gzip.log"); f << srv_time() << '\t' << v[5] << '\t' << s.size() << '\t' << s2.size() << std::endl; #endif if (s2.size() + 24 < s.size()) { h += "Content-Encoding: gzip\r\n"; s = to_string(s2); } } h += "\r\n"; #ifdef WIN32 m_write_b = shared_data(h.size() + s.size()); memcpy(m_write_b.data(), h); memcpy(m_write_b.data() + h.size(), s); int r = m_s.send(m_write_b); #else std::array<iovec, 2> d; d[0].iov_base = const_cast<char*>(h.data()); d[0].iov_len = h.size(); d[1].iov_base = const_cast<char*>(s.data()); d[1].iov_len = s.size(); msghdr m; m.msg_name = NULL; m.msg_namelen = 0; m.msg_iov = const_cast<iovec*>(d.data()); m.msg_iovlen = d.size(); m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; int r = sendmsg(m_s, &m, MSG_NOSIGNAL); #endif if (r == SOCKET_ERROR) { if (WSAGetLastError() != WSAECONNRESET) std::cerr << "send failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; } else if (r != h.size() + s.size()) { #ifndef WIN32 if (r < h.size()) { m_write_b = shared_data(h.size() + s.size()); memcpy(m_write_b.data(), h); memcpy(m_write_b.data() + h.size(), s); } else { m_write_b = make_shared_data(s); r -= h.size(); } #endif m_r = m_write_b; m_r.advance_begin(r); } if (m_r.empty()) m_write_b.clear(); }
static int handle_lua_request(struct mg_connection *conn) { struct mg_request_info *request_info = mg_get_request_info(conn); u_int len = (u_int)strlen(request_info->uri); char username[33] = { 0 }; if((ntop->getGlobals()->isShutdown()) //|| (strcmp(request_info->request_method, "GET")) || (ntop->getRedis() == NULL /* Starting up... */)) return(send_error(conn, 403 /* Forbidden */, request_info->uri, "Unexpected HTTP method or ntopng still starting up...")); if(ntop->get_HTTPserver()->is_ssl_enabled() && (!request_info->is_ssl)) redirect_to_ssl(conn, request_info); if(enable_users_login) { if((len > 4) && ((strcmp(&request_info->uri[len-4], ".css") == 0) || (strcmp(&request_info->uri[len-3], ".js")) == 0)) ; else if(!is_authorized(conn, request_info, username)) { redirect_to_login(conn, request_info); return(1); } else if(strcmp(request_info->uri, AUTHORIZE_URL) == 0) { authorize(conn, request_info); return(1); } } ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] %s", request_info->uri); if(strstr(request_info->uri, "//") || strstr(request_info->uri, "&&") || strstr(request_info->uri, "??") || strstr(request_info->uri, "..")) { ntop->getTrace()->traceEvent(TRACE_WARNING, "[HTTP] The URL %s is invalid/dangerous", request_info->uri); return(send_error(conn, 400 /* Bad Request */, request_info->uri, "The URL specified contains invalid/dangerous characters")); } if((strncmp(request_info->uri, "/lua/", 5) == 0) || (strcmp(request_info->uri, "/") == 0)) { /* Lua Script */ char path[255] = { 0 }, uri[2048]; struct stat buf; snprintf(path, sizeof(path), "%s%s", httpserver->get_scripts_dir(), (strlen(request_info->uri) == 1) ? "/lua/index.lua" : request_info->uri); ntop->fixPath(path); if((stat(path, &buf) == 0) && (S_ISREG (buf.st_mode))) { Lua *l = new Lua(); ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] %s [%s]", request_info->uri, path); if(l == NULL) { ntop->getTrace()->traceEvent(TRACE_ERROR, "[HTTP] Unable to start Lua interpreter"); return(send_error(conn, 500 /* Internal server error */, "Internal server error", "%s", "Unable to start Lua interpreter")); } else { l->handle_script_request(conn, request_info, path); delete l; return(1); /* Handled */ } } uri_encode(request_info->uri, uri, sizeof(uri)-1); return(send_error(conn, 404, "Not Found", PAGE_NOT_FOUND, uri)); } else { ntop->getTrace()->traceEvent(TRACE_INFO, "[HTTP] Serving file %s%s", ntop->get_HTTPserver()->get_docs_dir(), request_info->uri); return(0); /* This is a static document so let mongoose handle it */ } }
void Cconnection::read(const std::string& v) { #ifndef NDEBUG std::cout << v << std::endl; #endif if (m_server->config().m_log_access) { static std::ofstream f("xbt_tracker_raw.log"); f << m_server->time() << '\t' << inet_ntoa(m_a.sin_addr) << '\t' << ntohs(m_a.sin_port) << '\t' << v << std::endl; } Ctracker_input ti; size_t e = v.find('?'); if (e == std::string::npos) e = v.size(); else { size_t a = e + 1; size_t b = v.find(' ', a); if (b == std::string::npos) return; while (a < b) { size_t c = v.find('=', a); if (c++ == std::string::npos) break; size_t d = v.find_first_of(" &", c); if (d == std::string::npos) break; ti.set(v.substr(a, c - a - 1), uri_decode(v.substr(c, d - c))); a = d + 1; } } if (!ti.m_ipa || !is_private_ipa(m_a.sin_addr.s_addr)) ti.m_ipa = m_a.sin_addr.s_addr; std::string torrent_pass0; size_t a = 4; if (a < e && v[a] == '/') { a++; if (a + 1 < e && v[a + 1] == '/') a += 2; if (a + 32 < e && v[a + 32] == '/') { torrent_pass0 = v.substr(a, 32); a += 33; if (a + 40 < e && v[a + 40] == '/') a += 41; } } std::string h = "HTTP/1.0 200 OK\r\n"; Cvirtual_binary s; bool gzip = true; switch (a < v.size() ? v[a] : 0) { case 'a': if (!ti.valid()) break; gzip = false; if (0) s = Cbvalue().d(bts_failure_reason, bts_banned_client).read(); else { std::string error = m_server->insert_peer(ti, false, m_server->find_user_by_torrent_pass(torrent_pass0, ti.m_info_hash)); s = error.empty() ? m_server->select_peers(ti) : Cbvalue().d(bts_failure_reason, error).read(); } break; case 'd': if (m_server->config().m_debug) { gzip = m_server->config().m_gzip_debug; h += "Content-Type: text/html; charset=us-ascii\r\n"; s = Cvirtual_binary(m_server->debug(ti)); } break; case 's': if (v.size() >= 7 && v[6] == 't') { gzip = m_server->config().m_gzip_debug; h += "Content-Type: text/html; charset=us-ascii\r\n"; s = Cvirtual_binary(m_server->statistics()); } else if (m_server->config().m_full_scrape || ti.m_compact || !ti.m_info_hash.empty()) { gzip = m_server->config().m_gzip_scrape && !ti.m_compact && ti.m_info_hash.empty(); s = m_server->scrape(ti); } break; } if (s.empty()) { if (!ti.m_peer_id.empty() || m_server->config().m_redirect_url.empty()) h = "HTTP/1.0 404 Not Found\r\n"; else { h = "HTTP/1.0 302 Found\r\n" "Location: " + m_server->config().m_redirect_url + (ti.m_info_hash.empty() ? "" : "?info_hash=" + uri_encode(ti.m_info_hash)) + "\r\n"; } } else if (gzip) { Cvirtual_binary s2 = xcc_z::gzip(s); #ifndef NDEBUG static std::ofstream f("xbt_tracker_gzip.log"); f << m_server->time() << '\t' << v[5] << '\t' << s.size() << '\t' << s2.size() << std::endl; #endif if (s2.size() + 24 < s.size()) { h += "Content-Encoding: gzip\r\n"; s = s2; } } h += "\r\n"; #ifdef WIN32 m_write_b.resize(h.size() + s.size()); memcpy(m_write_b.data_edit(), h.data(), h.size()); s.read(m_write_b.data_edit() + h.size()); int r = m_s.send(m_write_b); #else boost::array<iovec, 2> d; d[0].iov_base = const_cast<char*>(h.data()); d[0].iov_len = h.size(); d[1].iov_base = const_cast<unsigned char*>(s.data()); d[1].iov_len = s.size(); msghdr m; m.msg_name = NULL; m.msg_namelen = 0; m.msg_iov = const_cast<iovec*>(d.data()); m.msg_iovlen = d.size(); m.msg_control = NULL; m.msg_controllen = 0; m.msg_flags = 0; int r = sendmsg(m_s, &m, MSG_NOSIGNAL); #endif if (r == SOCKET_ERROR) { if (WSAGetLastError() != WSAECONNRESET) std::cerr << "send failed: " << Csocket::error2a(WSAGetLastError()) << std::endl; } else if (r != h.size() + s.size()) { #ifndef WIN32 if (r < h.size()) { m_write_b.resize(h.size() + s.size()); memcpy(m_write_b.data_edit(), h.data(), h.size()); s.read(m_write_b.data_edit() + h.size()); } else { m_write_b = s; r -= h.size(); } #endif m_r = m_write_b; m_r += r; } if (m_r.empty()) m_write_b.clear(); }
/** * Encode URI field string * * @v field URI field index * @v string String * @v buf Buffer * @v len Length of buffer * @ret len Length of encoded string (excluding NUL) */ size_t uri_encode_string ( unsigned int field, const char *string, char *buf, ssize_t len ) { return uri_encode ( field, string, strlen ( string ), buf, len ); }