Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist
jninnes revised this gist . 1 changed file with 1 addition and 1 deletion. View gist @ b3b4a2a
client.c
2 
@@ -121,7 +121,7 @@ start_routine(CLIENT *client)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
#endif/*SIGNAL_CLIENT_PLATFORM*/
if (my.login == TRUE) {
- URL tmp = new_url(array_get(my.lurl, 0));
+ URL tmp = new_url(array_next(my.lurl));
url_set_ID(tmp, 0);
__request(C, tmp, client);
}
jninnes created this gist . View gist @ 1a5fe2f
client.c
759 
@@ -0,0 +1,759 @@
+/**
+ * HTTP/HTTPS client support
+ *
+ * Copyright (C) 2000-2014 by
+ * Jeffrey Fulmer - <jeff@joedog.org>, et al.
+ * This file is distributed as part of Siege
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <setup.h>
+#include <client.h>
+#include <signal.h>
+#include <sock.h>
+#include <ssl.h>
+#include <ftp.h>
+#include <http.h>
+#include <url.h>
+#include <util.h>
+#include <auth.h>
+#include <cookie.h>
+#include <date.h>
+#include <joedog/boolean.h>
+#include <joedog/defs.h>
+
+#if defined(hpux) || defined(__hpux) || defined(WINDOWS)
+#define SIGNAL_CLIENT_PLATFORM
+#endif
+
+/**
+ * local prototypes
+ */
+private BOOLEAN __request(CONN *C, URL U, CLIENT *c);
+private BOOLEAN __http(CONN *C, URL U, CLIENT *c);
+private BOOLEAN __ftp (CONN *C, URL U, CLIENT *c);
+private BOOLEAN __init_connection(CONN *C, URL U, CLIENT *c);
+private void __increment_failures();
+private int __select_color(int code);
+
+#ifdef SIGNAL_CLIENT_PLATFORM
+static void signal_handler( int i );
+static void signal_init();
+#else /*CANCEL_CLIENT_PLATFORM*/
+void clean_up();
+#endif/*SIGNAL_CLIENT_PLATFORM*/
+
+/**
+ * local variables
+ */
+#ifdef SIGNAL_CLIENT_PLATFORM
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+#endif/*SIGNAL_CLIENT_PLATFORM*/
+float himark = 0;
+float lomark = -1;
+
+/**
+ * The thread entry point for clients.
+ *
+ * #ifdef SIGNAL_CLIENT_PLATFORM
+ * the thread entry point for signal friendly clients.
+ * (currently only HP-UX and Windows)
+ *
+ * #ifndef SIGNAL_CLIENT_PLATFORM
+ * assume cancel client.
+ * thread entry point for cancellable friendly operating systems like
+ * aix, GNU/linux, solaris, bsd, etc.
+ */
+void *
+start_routine(CLIENT *client)
+{
+ int x, y; // loop counters, indices
+ int ret; //function return value
+ int len; // main loop length
+ CONN *C = NULL; // connection data (sock.h)
+
+#ifdef SIGNAL_CLIENT_PLATFORM
+ sigset_t sigs;
+#else
+ int type, state;
+#endif
+
+ C = xcalloc(sizeof(CONN), 1);
+ C->sock = -1;
+
+#ifdef SIGNAL_CLIENT_PLATFORM
+ pthread_once(&once, signal_init);
+ sigemptyset(&sigs);
+ sigaddset(&sigs, SIGUSR1);
+ pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
+#else
+ #if defined(_AIX)
+ pthread_cleanup_push((void(*)(void*))clean_up, NULL);
+ #else
+ pthread_cleanup_push((void*)clean_up, C);
+ #endif
+#endif /*SIGNAL_CLIENT_PLATFORM*/
+
+#ifdef SIGNAL_CLIENT_PLATFORM
+#else/*CANCEL_CLIENT_PLATFORM*/
+ #if defined(sun)
+ pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type);
+ #elif defined(_AIX)
+ pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type);
+ #elif defined(hpux) || defined(__hpux)
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &type);
+ #else
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &type);
+ #endif
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
+#endif/*SIGNAL_CLIENT_PLATFORM*/
+ if (my.login == TRUE) {
+ URL tmp = new_url(array_get(my.lurl, 0));
+ url_set_ID(tmp, 0);
+ __request(C, tmp, client);
+ }
+
+ len = (my.reps == -1) ? (int)array_length(client->urls) : my.reps;
+ y = (my.reps == -1) ? 0 : client->id * (my.length / my.cusers);
+ for (x = 0; x < len; x++, y++) {
+ x = ((my.secs > 0) && ((my.reps <= 0)||(my.reps == MAXREPS))) ? 0 : x;
+ if (my.internet == TRUE) {
+ y = (unsigned int) (((double)pthread_rand_np(&(client->rand_r_SEED)) /
+ ((double)RAND_MAX + 1) * my.length ) + .5);
+ y = (y >= my.length)?my.length-1:y;
+ y = (y < 0)?0:y;
+ } else {
+ /**
+ * URLs accessed sequentially; when reaching the end, start over
+ * with clean slate, ie. reset (delete) cookies (eg. to let a new
+ * session start)
+ */
+ if (y >= my.length) {
+ y = 0;
+ if (my.expire) {
+ delete_all_cookies(pthread_self());
+ }
+ }
+ }
+ if (y >= my.length || y < 0) {
+ y = 0;
+ }
+ URL tmp = array_get(client->urls, y);
+ if (tmp != NULL && url_get_hostname(tmp) != NULL) {
+ client->auth.bids.www = 0; /* reset */
+ if ((ret = __request(C, tmp, client))==FALSE) {
+ __increment_failures();
+ }
+ }
+
+ if (my.failures > 0 && my.failed >= my.failures) {
+ break;
+ }
+ }
+
+ #ifdef SIGNAL_CLIENT_PLATFORM
+ #else/*CANCEL_CLIENT_PLATFORM*/
+ /**
+ * every cleanup must have a pop
+ */
+ pthread_cleanup_pop(0);
+ #endif/*SIGNAL_CLIENT_PLATFORM*/
+ if (C->sock >= 0){
+ C->connection.reuse = 0;
+ socket_close(C);
+ }
+ xfree(C);
+ C = NULL;
+
+ return(NULL);
+}
+
+private BOOLEAN
+__request(CONN *C, URL U, CLIENT *client) {
+ C->scheme = url_get_scheme(U);
+
+ switch (C->scheme) {
+ case FTP:
+ return __ftp(C, U, client);
+ case HTTP:
+ case HTTPS:
+ default:
+ return __http(C, U, client);
+ }
+}
+
+/**
+ * HTTP client request.
+ * The protocol is executed in http.c
+ * This function invoked functions inside that module
+ * and it gathers statistics about the request.
+ */
+private BOOLEAN
+__http(CONN *C, URL U, CLIENT *client)
+{
+ unsigned long bytes = 0;
+ int code, fail;
+ float etime;
+ clock_t start, stop;
+ struct tms t_start, t_stop;
+ HEADERS *head;
+#ifdef HAVE_LOCALTIME_R
+ struct tm keepsake;
+#endif/*HAVE_LOCALTIME_R*/
+ time_t now;
+ struct tm *tmp;
+ size_t len;
+ char fmtime[65];
+ URL redirect_url = NULL;
+
+ if (my.csv) {
+ now = time(NULL);
+#ifdef HAVE_LOCALTIME_R
+ tmp = (struct tm *)localtime_r(&now, &keepsake);
+#else
+ tmp = localtime(&now);
+#endif/*HAVE_LOCALTIME_R*/
+ if (tmp) len = strftime(fmtime, 64, "%Y-%m-%d %H:%M:%S", tmp);
+ else snprintf(fmtime, 64, "n/a");
+ }
+
+ if (url_get_scheme(U) == UNSUPPORTED) {
+ if (my.verbose && !my.get) {
+ NOTIFY (
+ ERROR,
+ "%s %d %6.2f secs: %7d bytes ==> %s\n",
+ "UNSPPRTD", 501, 0.00, 0, "PROTOCOL NOT SUPPORTED BY SIEGE"
+ );
+ } /* end if my.verbose */
+ return FALSE;
+ }
+
+ if (my.delay) {
+ pthread_sleep_np(
+ (unsigned int) (((double)pthread_rand_np(&(client->rand_r_SEED)) /
+ ((double)RAND_MAX + 1) * my.delay ) + .5)
+ );
+ }
+
+ /* record transaction start time */
+ start = times(&t_start);
+
+ if (! __init_connection(C, U, client)) return FALSE;
+
+ /**
+ * write to socket with a GET/POST/PUT/DELETE/HEAD
+ */
+ if (url_get_method(U) == GET || url_get_method(U) == HEAD) {
+ if ((http_get(C, U)) == FALSE) {
+ C->connection.reuse = 0;
+ socket_close(C);
+ return FALSE;
+ }
+ } else {
+ if ((http_post(C, U)) == FALSE) {
+ C->connection.reuse = 0;
+ socket_close(C);
+ return FALSE;
+ }
+ }
+
+ /**
+ * read from socket and collect statistics.
+ */
+ if ((head = http_read_headers(C, U))==NULL) {
+ C->connection.reuse = 0;
+ socket_close(C);
+ echo ("%s:%d NULL headers", __FILE__, __LINE__);
+ return FALSE;
+ }
+
+ bytes = http_read(C);
+
+ if (!my.zero_ok && (bytes < 1)) {
+ C->connection.reuse = 0;
+ socket_close(C);
+ http_free_headers(head);
+ echo ("%s:%d zero bytes back from server", __FILE__, __LINE__);
+ return FALSE;
+ }
+ stop = times(&t_stop);
+ etime = elapsed_time(stop - start);
+ code = (head->code < 400 || head->code == 401 || head->code == 407) ? 1 : 0;
+ fail = (head->code >= 400 && head->code != 401 && head->code != 407) ? 1 : 0;
+ /**
+ * quantify the statistics for this client.
+ */
+ client->bytes += bytes;
+ client->time += etime;
+ client->code += code;
+ client->fail += fail;
+ if (head->code == 200) {
+ client->ok200++;
+ }
+
+ /**
+ * check to see if this transaction is the longest or shortest
+ */
+ if (etime > himark) {
+ himark = etime;
+ }
+ if ((lomark < 0) || (etime < lomark)) {
+ lomark = etime;
+ }
+ client->himark = himark;
+ client->lomark = lomark;
+
+ /**
+ * verbose output, print statistics to stdout
+ */
+ if ((my.verbose && !my.get) && (!my.debug)) {
+ int color = __select_color(head->code);
+ char *time_str = (my.timestamp==TRUE)?timestamp():"";
+ if (my.csv) {
+ if (my.display)
+ DISPLAY(color, "%s%s%s%4d,%s,%d,%6.2f,%7lu,%s,%d,%s",
+ time_str, (my.mark)?my.markstr:"", (my.mark)?",":"", client->id, head->head, head->code,
+ etime, bytes, url_get_display(U), url_get_ID(U), fmtime
+ );
+ else
+ DISPLAY(color, "%s%s%s%s,%d,%6.2f,%7lu,%s,%d,%s",
+ time_str, (my.mark)?my.markstr:"", (my.mark)?",":"", head->head, head->code,
+ etime, bytes, url_get_display(U), url_get_ID(U), fmtime
+ );
+ } else {
+ if (my.display)
+ DISPLAY(
+ color, "%s%4d: %s %d %6.2f secs: %7lu bytes ==> %-4s %s", client->id,
+ time_str, head->head, head->code, etime, bytes, url_get_method_name(U),
+ url_get_display(U)
+ );
+ else
+ DISPLAY (
+ color, "%s%s %d %6.2f secs: %7lu bytes ==> %-4s %s",
+ time_str, head->head, head->code, etime, bytes, url_get_method_name(U),
+ url_get_display(U)
+ );
+ } /* else not my.csv */
+ if (my.timestamp) xfree(time_str);
+ }
+
+ /**
+ * close the socket and free memory.
+ */
+ if (!my.keepalive) {
+ socket_close(C);
+ }
+
+ /**
+ * deal with HTTP > 300
+ */
+ switch (head->code) {
+ case 301:
+ case 302:
+ case 303:
+ case 307:
+ if (my.follow && head->redirect[0]) {
+ /**
+ * XXX: What if the server sends us
+ * Location: path/file.htm
+ * OR
+ * Location: /path/file.htm
+ */
+ redirect_url = url_normalize(U, head->redirect); //new_url(head->redirect);
+
+ if (empty(url_get_hostname(redirect_url))) {
+ url_set_hostname(redirect_url, url_get_hostname(U));
+ }
+ if (head->code == 307) {
+ url_set_conttype(redirect_url,url_get_conttype(U));
+ url_set_method(redirect_url, url_get_method(U));
+
+ if (url_get_method(redirect_url) == POST) {
+ url_set_postdata(redirect_url, url_get_postdata(U), url_get_postlen(U));
+ }
+ }
+ if ((__request(C, redirect_url, client)) == FALSE) {
+ redirect_url = url_destroy(redirect_url);
+ return FALSE;
+ }
+ }
+ redirect_url = url_destroy(redirect_url);
+ break;
+ case 401:
+ /**
+ * WWW-Authenticate challenge from the WWW server
+ */
+ client->auth.www = (client->auth.www==0)?1:client->auth.www;
+ if ((client->auth.bids.www++) < my.bids - 1) {
+ BOOLEAN b;
+ if (head->auth.type.www == DIGEST) {
+ client->auth.type.www = DIGEST;
+ b = auth_set_digest_header(
+ my.auth, &(client->auth.wchlg), &(client->auth.wcred), &(client->rand_r_SEED),
+ head->auth.realm.www, head->auth.challenge.www
+ );
+ if (b == FALSE) {
+ NOTIFY(ERROR, "unable to set digest header");
+ return FALSE;
+ }
+ }
+ if (head->auth.type.www == BASIC) {
+ client->auth.type.www = BASIC;
+ auth_set_basic_header(my.auth, HTTP, head->auth.realm.www);
+ }
+ if ((__request(C, U, client)) == FALSE) {
+ fprintf(stderr, "ERROR from http_request\n");
+ return FALSE;
+ }
+ }
+ break;
+ case 407:
+ /**
+ * Proxy-Authenticate challenge from the proxy server.
+ */
+ client->auth.proxy = (client->auth.proxy==0)?1:client->auth.proxy;
+ if ((client->auth.bids.proxy++) < my.bids - 1) {
+ if (head->auth.type.proxy == DIGEST) {
+ BOOLEAN b;
+ client->auth.type.proxy = DIGEST;
+ b = auth_set_digest_header(
+ my.auth, &(client->auth.pchlg), &(client->auth.pcred), &(client->rand_r_SEED),
+ head->auth.realm.proxy, head->auth.challenge.proxy
+ );
+ if (b == FALSE) {
+ NOTIFY(ERROR, "unable to set digest header");
+ return FALSE;
+ }
+ }
+ if (head->auth.type.proxy == BASIC) {
+ client->auth.type.proxy = BASIC;
+ auth_set_basic_header(my.auth, PROXY, head->auth.realm.proxy);
+ }
+ if ((__request(C, U, client)) == FALSE)
+ return FALSE;
+ }
+ break;
+ case 408:
+ case 500:
+ case 501:
+ case 502:
+ case 503:
+ case 504:
+ case 505:
+ case 506:
+ case 507:
+ case 508:
+ case 509:
+ return FALSE;
+ default:
+ break;
+ }
+
+ client->hits ++;
+ http_free_headers(head);
+
+ return TRUE;
+}
+
+/**
+ * HTTP client request.
+ * The protocol is executed in http.c
+ * This function invoked functions inside that module
+ * and it gathers statistics about the request.
+ */
+private BOOLEAN
+__ftp(CONN *C, URL U, CLIENT *client)
+{
+ int pass;
+ int fail;
+ int code = 0; // capture the relevent return code
+ float etime; // elapsed time
+ CONN *D = NULL; // FTP data connection
+ size_t bytes = 0; // bytes from server
+ clock_t start, stop;
+ struct tms t_start, t_stop;
+
+ D = xcalloc(sizeof(CONN), 1);
+ D->sock = -1;
+
+ if (! __init_connection(C, U, client)) {
+ NOTIFY (
+ ERROR, "%s:%d connection failed %s:%d",
+ __FILE__, __LINE__, url_get_hostname(U), url_get_port(U)
+ );
+ xfree(D);
+ return FALSE;
+ }
+
+ start = times(&t_start);
+ if (C->sock < 0) {
+ NOTIFY (
+ ERROR, "%s:%d connection failed %s:%d",
+ __FILE__, __LINE__, url_get_hostname(U), url_get_port(U)
+ );
+ socket_close(C);
+ xfree(D);
+ return FALSE;
+ }
+
+ if (url_get_username(U) == NULL || strlen(url_get_username(U)) < 1) {
+ url_set_username(U, auth_get_ftp_username(my.auth, url_get_hostname(U)));
+ }
+
+ if (url_get_password(U) == NULL || strlen(url_get_password(U)) < 1) {
+ url_set_password(U, auth_get_ftp_password(my.auth, url_get_hostname(U)));
+ }
+
+ if (ftp_login(C, U) == FALSE) {
+ if (my.verbose) {
+ int color = __select_color(C->ftp.code);
+ DISPLAY (
+ color, "FTP/%d %6.2f secs: %7lu bytes ==> %-6s %s",
+ C->ftp.code, 0.0, bytes, url_get_method_name(U), url_get_request(U)
+ );
+ }
+ xfree(D);
+ client->fail += 1;
+ return FALSE;
+ }
+
+ ftp_pasv(C);
+ if (C->ftp.pasv == TRUE) {
+ debug("Connecting to: %s:%d", C->ftp.host, C->ftp.port);
+ D->sock = new_socket(D, C->ftp.host, C->ftp.port);
+ if (D->sock < 0) {
+ debug (
+ "%s:%d connection failed. error %d(%s)",__FILE__, __LINE__, errno,strerror(errno)
+ );
+ client->fail += 1;
+ socket_close(D);
+ xfree(D);
+ return FALSE;
+ }
+ }
+ if (url_get_method(U) == POST || url_get_method(U) == PUT) {
+ ftp_stor(C, U);
+ bytes = ftp_put(D, U);
+ code = C->ftp.code;
+ } else {
+ if (ftp_size(C, U) == TRUE) {
+ if (ftp_retr(C, U) == TRUE) {
+ bytes = ftp_get(D, U, C->ftp.size);
+ }
+ }
+ code = C->ftp.code;
+ }
+ socket_close(D);
+ ftp_quit(C);
+
+ pass = (bytes == C->ftp.size) ? 1 : 0;
+ fail = (pass == 0) ? 1 : 0;
+ stop = times(&t_stop);
+ etime = elapsed_time(stop - start);
+ client->bytes += bytes;
+ client->time += etime;
+ client->code += pass;
+ client->fail += fail;
+
+ /**
+ * check to see if this transaction is the longest or shortest
+ */
+ if (etime > himark) {
+ himark = etime;
+ }
+ if ((lomark < 0) || (etime < lomark)) {
+ lomark = etime;
+ }
+ client->himark = himark;
+ client->lomark = lomark;
+
+ if (my.verbose) {
+ int color = __select_color(code);
+ DISPLAY (
+ color, "FTP/%d %6.2f secs: %7lu bytes ==> %-6s %s",
+ code, etime, bytes, url_get_method_name(U), url_get_request(U)
+ );
+ }
+ client->hits++;
+ xfree(D);
+ return TRUE;
+}
+
+#ifdef SIGNAL_CLIENT_PLATFORM
+private void
+signal_handler(int sig)
+{
+ pthread_exit(&sig);
+}
+
+private void
+signal_init()
+{
+ struct sigaction sa;
+
+ sa.sa_handler = signal_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGUSR1, &sa, NULL);
+}
+#else/*CANCEL_CLIENT_PLATFORM*/
+
+void
+clean_up()
+{
+ return;
+}
+#endif
+
+private BOOLEAN
+__init_connection(CONN *C, URL U, CLIENT *client)
+{
+ C->pos_ini = 0;
+ C->inbuffer = 0;
+ C->content.transfer = NONE;
+ C->content.length = 0;
+ C->connection.keepalive = (C->connection.max==1)?0:my.keepalive;
+ C->connection.reuse = (C->connection.max==1)?0:my.keepalive;
+ C->connection.tested = (C->connection.tested==0)?1:C->connection.tested;
+ C->auth.www = client->auth.www;
+ C->auth.wchlg = client->auth.wchlg;
+ C->auth.wcred = client->auth.wcred;
+ C->auth.proxy = client->auth.proxy;
+ C->auth.pchlg = client->auth.pchlg;
+ C->auth.pcred = client->auth.pcred;
+ C->auth.type.www = client->auth.type.www;
+ C->auth.type.proxy = client->auth.type.proxy;
+ memset(C->buffer, 0, sizeof(C->buffer));
+
+ debug (
+ "%s:%d attempting connection to %s:%d",
+ __FILE__, __LINE__,
+ (auth_get_proxy_required(my.auth))?auth_get_proxy_host(my.auth):url_get_hostname(U),
+ (auth_get_proxy_required(my.auth))?auth_get_proxy_port(my.auth):url_get_port(U)
+ );
+
+ if (!C->connection.reuse || C->connection.status == 0) {
+ if (auth_get_proxy_required(my.auth)) {
+ debug (
+ "%s:%d creating new socket: %s:%d",
+ __FILE__, __LINE__, auth_get_proxy_host(my.auth), auth_get_proxy_port(my.auth)
+ );
+ C->sock = new_socket(C, auth_get_proxy_host(my.auth), auth_get_proxy_port(my.auth));
+ } else {
+ debug (
+ "%s:%d creating new socket: %s:%d",
+ __FILE__, __LINE__, url_get_hostname(U), url_get_port(U)
+ );
+ C->sock = new_socket(C, url_get_hostname(U), url_get_port(U));
+ }
+ }
+
+ if (my.keepalive) {
+ C->connection.reuse = TRUE;
+ }
+
+ if (C->sock < 0) {
+ debug (
+ "%s:%d connection failed. error %d(%s)",__FILE__, __LINE__, errno,strerror(errno)
+ );
+ socket_close(C);
+ return FALSE;
+ }
+
+ debug (
+ "%s:%d good socket connection: %s:%d",
+ __FILE__, __LINE__,
+ (auth_get_proxy_required(my.auth))?auth_get_proxy_host(my.auth):url_get_hostname(U),
+ (auth_get_proxy_required(my.auth))?auth_get_proxy_port(my.auth):url_get_port(U)
+ );
+
+ if (C->encrypt == TRUE) {
+ if (auth_get_proxy_required(my.auth)) {
+ https_tunnel_request(C, url_get_hostname(U), url_get_port(U));
+ https_tunnel_response(C);
+ }
+ C->encrypt = TRUE;
+ if (SSL_initialize(C)==FALSE) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+private void
+__increment_failures()
+{
+ pthread_mutex_lock(&(my.lock));
+ my.failed++;
+ pthread_mutex_unlock(&(my.lock));
+ pthread_testcancel();
+}
+
+
+private int
+__select_color(int code)
+{
+ switch(code) {
+ case 150:
+ case 200:
+ case 201:
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ case 206:
+ case 226:
+ return BLUE;
+ case 300:
+ case 301:
+ case 302:
+ case 303:
+ case 304:
+ case 305:
+ case 306:
+ case 307:
+ return CYAN;
+ case 400:
+ case 401:
+ case 402:
+ case 403:
+ case 404:
+ case 405:
+ case 406:
+ case 407:
+ case 408:
+ case 409:
+ case 410:
+ case 411:
+ case 412:
+ case 413:
+ case 414:
+ case 415:
+ case 416:
+ case 417:
+ return MAGENTA;
+ case 500:
+ case 501:
+ case 502:
+ case 503:
+ case 504:
+ case 505:
+ default: // WTF?
+ return RED;
+ }
+ return RED;
+}
+
Something went wrong with that request. Please try again.