Path: csiph.com!news.swapon.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Stefan Reuther Newsgroups: de.comp.lang.javascript Subject: Re: HTTP POST? Date: Fri, 14 Jun 2019 18:08:35 +0200 Lines: 244 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: 8bit X-Trace: individual.net PKwG6ORob/cgwC9GWcIJSgFNHBWwr8ojT4D+Is/hB7TZT5KqQk Cancel-Lock: sha1:Fqz1yYFlrcy/v8X+KioVimF+Qj8= User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 Hamster/2.1.0.1538 In-Reply-To: Xref: csiph.com de.comp.lang.javascript:5130 Am 12.06.2019 um 23:28 schrieb Ulli Horlacher: > Stefan Reuther wrote: >> Ich gehe natürlich davon aus, dass ein Übertragungsratenmesstool als >> Gegenseite einen Übertragensratenmesstoolserver hat und keinen >> generischen HTTP-Server mit Server-Architektur der 90er. Der Server >> sollte schon da sein, und nicht erst vom inetd gestartet werden. >> >> Einen solchen Server von Null an zu schreiben ist wirklich kein Hexenwerk. > > Bitte, mach das, wenn das doch SO einfach ist. Siehe unten, knappe Dreiviertelstunde. Kann sicher noch ein, zwei Reviews vertragen, und etwas Härtung gegen DoS/Teergrube, etwas verbesserte Protokollparserei. Ebenso wäre eine spannende Übung, poll() zu verwenden und auf fork() zu verzichten. Getestet mit curl und wget. 100k-Download: wget http://127.0.0.1:8000/filename?size=100000 Einen HTTP-Server zu hacken würde ich heute fast als Grundqualifikation sehen. Das schöne an den RfC-Protokollen ist, dass man mit erstaunlich wenig Aufwand erstaunlich viel erreichen kann. >>>> Und all das lässt sich durch Vergrößerung der Datenmenge reduzieren. >>>> Mehr Daten in der Payload = Kernel hat immer was zu senden = Overhead >>>> geht besser unter. >>> >>> Meine Server machen ca 5 GB/s Durchsatz. In dem Bereich muesste ich Daten >>> verschicken um den Overhead zu minimieren. Das ist bei langsamer >>> Client-Anbindung (DSL, WLAN, etc) unbrauchbar. >> >> Deswegen adaptiv. Wie lange brauchen 64k? Wenn unter einer Sekunde: wie >> lange brauchen 256k? Und so weiter. > > Auch das ist zu viel Overhead und verfaelscht das Ergebnis. Irgendwie gewinne ich schon den Eindruck, du willst nur hören/sagen, dass alles doof ist, aber nur keine Lösung. Adaptiv = solange die Parameter austarieren, bis der Overhead verschwindet, dann messen. >>> Einen Proxy kannst du nicht beeinflussen. Du musst den benutzen, so, wie >>> er ist. >> >> Eine synthetische Bandbreitenmessung über einen Proxy ist aber auch >> ziemlich absurd. > > Manche Leute kommen nur ueber einen Proxy ins Internet. > Die wollen trozdem wissen, wie schnell es geht. > Mit meinem tcpbm koennen sie das feststellen. Dann wissen sie, wie schnell HTTP über den Proxy geht. Das wissen sie aber auch, wenn sie einen Up- oder Download machen. Und dann wissen sie nicht, wie schnell ein nicht auf HTTP basierendes Protokoll ist. F*EX war doch sowas? Stefan ----8<--------8<----[nullserver.c]----8<--------8<---- /* * Quick & Dirty HTTP server * * Accepts any request. * POST data is just swallowed. * If the request URI contains a "size=N" token, that is the size of the response in bytes. */ #include #include #include #include #include #include #include #include #include #include #include #define PORT 8000 #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define CHECK(x) check(x, #x) static int check(int result, const char* what) { if (result == -1) { fprintf(stderr, "error in %s: %s\n", what, strerror(errno)); exit(1); } return result; } static int read_line(int fd, char* buf, size_t len) { char ch; while (1) { if (read(fd, &ch, 1) != 1) { return 0; } if (ch == '\n') { *buf = '\0'; return 1; } if (ch != '\r' && len > 1) { *buf++ = tolower((unsigned char) ch); --len; } } } static void handle_connection(int fd) { static const char zeroes[16384] = {}; char buffer[16384]; while (1) { // Read first line if (!read_line(fd, buffer, sizeof buffer)) { // Probably means they closed the connection although it was a keepalive connection return; } // Check parameters int is_post = (strncmp(buffer, "post", 4) == 0); int keepalive = (strstr(buffer, "http/1.1") != 0); size_t result_size = 0; char* p = strstr(buffer, "size="); if (p) { result_size = strtoul(p+5, 0, 10); } size_t post_size = 0; // Read header while (1) { if (!read_line(fd, buffer, sizeof buffer)) { printf("Failed to read header line\n"); return; } if (buffer[0] == '\0') { break; } if (strncmp(buffer, "content-length:", 15) == 0) { post_size = strtoul(buffer+15, 0, 0); } if (strncmp(buffer, "connection:", 11) == 0) { keepalive = strstr(buffer, "keep-alive") != 0; } } printf("Request: upload %zd bytes, download %zd bytes\n", post_size, result_size); // For POST, read body while (is_post && post_size > 0) { int n = read(fd, buffer, MIN(post_size, sizeof buffer)); if (n <= 0) { printf("Failed to read POST body\n"); return; } post_size -= n; } // Response header sprintf(buffer, "HTTP/1.1 200 OK\r\n" "Connection: %s\r\n" "Content-Type: application/octet-stream\r\n" "Content-Length: %zd\r\n\r\n", keepalive ? "keep-alive" : "close", result_size); if (write(fd, buffer, strlen(buffer)) != (int)strlen(buffer)) { printf("Failed to write response header\n"); return; } // Send response while (result_size > 0) { int n = write(fd, zeroes, MIN(result_size, sizeof(zeroes))); if (n <= 0) { printf("Failed to write response\n"); return; } result_size -= n; } if (!keepalive) { break; } } } int main() { // Set up a socket int listen_fd; struct sockaddr_in me; CHECK(listen_fd = socket(AF_INET, SOCK_STREAM, 0)); int one = 1; CHECK(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))); me.sin_family = AF_INET; me.sin_port = htons(PORT); me.sin_addr.s_addr = 0; CHECK(bind(listen_fd, (struct sockaddr*)&me, sizeof(me))); CHECK(listen(listen_fd, 10)); // Main loop printf("Listening...\n"); while (1) { struct sockaddr_in them; socklen_t their_size = sizeof(them); int connection_fd; CHECK(connection_fd = accept(listen_fd, (struct sockaddr*)&them, &their_size)); struct timeval tv; tv.tv_sec = 10; tv.tv_usec = 0; CHECK(setsockopt(connection_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))); CHECK(setsockopt(connection_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv))); pid_t pid = fork(); if (pid == 0) { // Child close(listen_fd); handle_connection(connection_fd); close(connection_fd); _exit(0); } else { // Parent printf("Got connection fd=%d, pid=%d\n", connection_fd, (int) pid); close(connection_fd); // Reap ripe children pid_t other_child; int status; while ((other_child = waitpid(-1, &status, WNOHANG)) > 0) { printf("Child %d done\n", (int) other_child); } } } }