diff --git a/client/HTTPServer.cpp b/client/HTTPServer.cpp index 617be9b5..f09289fc 100644 --- a/client/HTTPServer.cpp +++ b/client/HTTPServer.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include "util/base64.h" #include "util/Log.h" +#include "util/util.h" #include "tunnel/Tunnel.h" #include "tunnel/TransitTunnel.h" #include "transport/Transports.h" @@ -18,977 +20,194 @@ // For image and info #include "version.h" -namespace i2p +namespace i2p { +namespace util { + +const char HTTP_COMMAND_TUNNELS[] = "tunnels"; +const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels"; +const char HTTP_COMMAND_TRANSPORTS[] = "transports"; +const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; +const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; +const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; +const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; +const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; +const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions"; +const char HTTP_COMMAND_SAM_SESSION[] = "sam_session"; +const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; + +void HTTPConnection::Terminate() { -namespace util -{ - - const std::string HTTPConnection::itoopieImage = - "\"ICToopie"; - - const std::string HTTPConnection::itoopieFavicon = - "data:image/vnd.microsoft.icon;base64," - "AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAABsAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgQAAAIMAAACEAAAAg" - "wAAAIAAAACCAAAASQAAACUAAAAmAAAAOwAAAFIAAABgAAAAVAAAACcAAAAVAAAADQAAAAcAAAADAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjAAAA/wAAAP4AAAD+AAAA/gAAAP4AAAD+A" - "AAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/" - "AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAACbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAP8AA" - "AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4A" - "AAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/wAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAKQAAAAAAAAAAAAAAAADbAAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/gAA" - "AP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAIA/gAAAPwAAAD/AAAA/gAAAP4AAAD+AAAA/gA" - "AAP4AAAD+AAAA/wAAAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApAAAAAAAAAAAAHAAAAP8AAAD+AAAA/gAAAPwACwD9ABEA" - "/QASAPgAFgD4ABUA+AATAP0ADQD8AAIA/AAAAP8AAAD+AAAA/gAAAP8ADQD7ACMA/QAlAP8AJwD/ACI" - "A/QATAPwAAAD8AAAA/gAAAP4AAAD+AAAA/gAAAKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe" - "AAAA/gAAAPwAJAD+AAwA+wAAAP8AAAD/AAAA/wAEAPwAEgD8ACQA/gAmAP8AHAD8AAEA/gAAAP4ACwD" - "8ACUA/wAkAP8AFwD8AAkA/AAQAP0AIwD+ACQA/wANAPsAAAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAEAAABNAAAA/wAAAP8AGAD8AAAA/QAYAPMARQDyAFEA9wBOAPIAPAD0ABEA8QAAAP8" - "AGgD7ACMA/wAVAP0AAAD9ACMA/QAkAP8ADwD9AAgA+ABBAPUALADyAAAA/AAUAPwAJgD/ABgA/AAAAP" - "0AAAD/AAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAP4ADQD8AAgA/wAqAPAAcAD/AGoA/wB" - "qAP8AagD/AGoA/wBvAP8ATwDvAAAA/QAbAP0AEwD8AAYA/QAkAP8AGAD8AAsA9wBuAPgAagD/AGsA/w" - "BjAPkADAD3AAQA/QAiAP4AGgD9AAAA/gAAAP8AAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZgAAAP8AAAD+ABY" - "A+wAQAPQAcQD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBTAPEAAAD/AAcA/AAMAPwAIQD9AA" - "AA+gBoAPgAagD/AGoA/wBqAP8AagD/AHAA/gAuAO0AAAD/AB8A/QAPAPwAAAD+AAAA+AAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAANIAAAD+AAwA+QAAAP0AZQD1AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8Abg" - "D/ABcA8QAAAP4ACAD9AAAA+QBeAPkAagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AbQD/ADkA7wAAAP8AJ" - "AD9AAAA/gAAAP8AAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAALi8AAAAAAAAAAAAAAAD/AAAA/QAAAP8AKwD1AGsA/wBqAP8AagD/AGoA/wBqAP" - "8AagD/AGoA/wBqAP8AagD/AGoA/wA9APUAAAD/AAAA/wBKAPMAagD/AGoA/wBqAP8AagD/AGoA/wBqA" - "P8AagD/AGoA/wBxAP8ADgD1ABMA/AAHAPsAAAD/AAAARQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPAIAAAAgAAAA/wAAAPwAAAD/AGQA9A" - "BqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8ASQD1AAAA/wASAPMAcAD/AGoA/" - "wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AawD/ACsA+QAOAP4ADQD8AAAA/wAAAEUAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7gAAAAAAAADgwAQAYLwAA//8AAA" - "ICIwAAAP8AAAD+AAYA8wBwAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/A" - "EIA9QAAAP8AMADvAGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGsA/wApAP0AEQD8" - "AAIA/QAAAP8AAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAVgEAAA" - "AAACJ5AQA2ygAAND8BAHV+AgAAAAAAAAH/AAAA/gAcAPQAbAD/AGoA/wBqAP8AagD/AGoA/wBqAP8Aa" - "gD/AGoA/wBqAP8AagD/AGsA/wApAPYAAAD+AB4A+gBsAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8A" - "agD/AGoA/wBrAP8ALADxAAAA/AAAAP4AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAABYAhQAfAE8ABgBWAQAAAAAAIoABAAAAAAA5UgEAAAAAAAAA+AAAAP4AJQD2AGsA/wBqA" - "P8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBsAPgAAAD6AAAA/gANAPAAbgD/AGoA/wBq" - "AP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/ADsA+QAAAP8AAAD+AAAA4AAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtQAAAAAAAABYABgAZgEGAIMBAAAAAAA+fgEAAAAAAAAAA" - "AACA8wAAAH+ACkA9wBgAPgARQDwADoA9gA5APYASgD0AHAA9wBrAP8AagD/AGoA/wBxAP0AFQD0AAAA" - "/gAAAP4AAAD5AHMA/QBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBvAP0ATgDxAEwA9AA1AOkAAAD/AAA" - "A/gAAAP8AAAB3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAvAAzAKcBAADXAAAAAAAcAFYBF" - "gB4ASAAZwEAXT8BADpdAgAAAAAAAQG+AAEB/gAAAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAPsAJAD1" - "AEQA9ABEAPMACQD3AAAA/wAAAP4AAAD+AAAA/wAiAPMASAD4AE8A9gBuAPgAbQD/AGoA/wBvAP8AFQD" - "yAAAA/wAAAP8AAAD/AAAA/gAAAP4AAAD+AAAA/wAAABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "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" - "f7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf8/wCq5v4AERj+AAEA/gAAAP4AAAD+A" - "AAA/gAAAP4AAAD/AAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAD+AAAA/gAAAP4Aeqf9ALz//wC3+/8At/" - "v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At" - "/r/ALz//gAcJvwAAQH+AAAA/gAAAP4AAAD/AAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI0AAAD/AAAA/gAAAP" - "4Ac579ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+" - "/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Avf/+ABcg/QAAAf4AAAD+AAAA/wAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAABIAAAD/AAAA/gAAAP4AP1X9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/" - "wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wCy8v4AAAD+AAAA" - "/gAAAP8AAACKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAACoAAAA/QAAAP4ABAb9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/A" - "Lf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/" - "ALf7/wC3+/8Atvr/AHmm/QAAAP4AAAD+AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA/wAAAP4AAAD+AHWh/QC2+v8At" - "/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8A" - "t/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDD//8AGSP9AAAA/gAAAP8AAABuAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAA" - "P8AAAD+AAUH/QDE//8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3" - "+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atvv/AH+s/gA" - "AAP4AAAD+AAAA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAALMAAAD+AAAA/gBZd/0At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7" - "/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf" - "7/wC3+/8At/v/ALf7/wDF//8AAAD9AAAA/gAAAP8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAA/gAAAP4Al9D9ALf7/wC3+/8At/v/" - "ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v" - "/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Auf7/AERe/QAAAP4AAAD/AAAAUQAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP4A" - "AAD9AMb//gC3+/8At/v/ALf7/wC3+/8Auf7/AMb//gC2+f4AwP/+AMT//wC4/f8At/v/ALf7/wC3+/8" - "At/v/ALf7/wC3+/8At/v/ALf7/wC8//8Avf//ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALb7/wBvlf" - "4AAAD+AAAA/gAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAACgAAAP8AAAD+ABgg/QDA//8At/v/ALf7/wC2+v8AuPz+AEVe/QAAAP0AAAD+AAAA/gA" - "EBv0AU2/9ALz//wC3+/8At/v/ALf7/wC3+/8Atvr/AL7//wBmi/0ALj/9ACQx/QBJZP0Ai739AMD//w" - "C3+/8At/v/ALf7/wC3+/8Aksj+AAAA/gAAAP4AAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAAAD/AAAA/gAtPf4AvP//ALf7/wC3+/8As/T+AAo" - "O/QAAAP0SEhLtAAAA/gAAAP4AAAD+AAAA/gAWH/0Av///ALf7/wC3+/8At/v/ALHx/gANEv0AAAD+AA" - "AA/gAAAP4AAAD/AAAA/wAuP/0Avv//ALf7/wC3+/8At/v/AKjm/QAAAP4AAAD+AAAApwAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAA/wAAAP4AL0H" - "+ALz//wC3+/8AvP//ADJE/QAAAPfc3Nz1TExM6wAAAP4AAAD+AAAA/gAAAP8AAAD+AGeN/gC3+/8At/" - "v/AML//wAeKf0AAAH/AAAA/gAAAP4AAAD+cXFx3YSEhOoAAAD9AEVe/QC6//8At/v/ALf7/wCs7P8AA" - "AD+AAAA/gAAAKEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAP8AAAD+ACAt/QC+//8At/v/ALP1/gAAAP95eXns/////2FhYeoBAQH/AAAA/gEBAf" - "9eXl7lDQ0N9gAgLP0Av///ALf7/wCNwf4AAAD/NDQ03AAAAP8AAAD+AAAA/6Ojo+b/////eXl55AAAA" - "P8AtPf+ALf7/wC3+/8AoNv9AAAA/gAAAP4AAACHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/gAAAP0Ax///ALf7/wCIu/0AAAD/ysrK6/" - "/////8/Pz6Hx8f6wAAAP8kJCTm/f39/WVlZe4ABAX8AMT//wC3/P8AV3X9ERER7/////9MTEzrAAAA6" - "ElJSeb///////////X19e8AAAD/AHuo/QC3+/8At/v/AIW2/gAAAP4AAAD/AAAAZAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0wAAAP4AAAD+AK" - "fl/gC3+/8AjcH+AAAA/83Nze/////////////////////w//////////9gYGDsAA8V/QDC//8Auv//A" - "EJa/UFBQeb////////////////////////////////////vAAAA/wBvlfwAt/v/ALf7/wBdff0AAAD+" - "AAAA/wAAAC0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAI4AAAD+AAAA/gBnjP0At/v/ALz//gAAAP+CgoLx/////////////////////////////" - "///CAkJ8QBCXP4Auf7/ALj8/wBScf0DAwPw////////////////////////////////tra26AAAAP8A" - "hrf+ALf7/wDA//8AHCf9AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3AAAA/wAAAP4AEBb9AMT//wC6//8AQVn+AAAA9+Pj4" - "/L/////////////////////cnJy1gAAAP8AlMr9ALf7/wC3+/8AhLT+AAAA/5mZmeL/////////////" - "/////////////R0dHesAAAD9AL///gC3+/8ApuX+AAAA/gAAAP4AAAC1AAAAAAAAAAAAAAAAAAAAAAA" - "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" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMAAAD/AAAA/gAAAP4AAAD9AFl3/QCt7/4AwP//ALj9/w" - "C2+/8At/v/ALf7/wC3+/8At/v/ALz//wDB//4AeKP+ABki/QAAAP4AAAD+AAAA/wAAAOEAAAASAAAAA" - "QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAOUAAAD/AA" - "AA/gAAAP4AAAD+ABcg/QBQbv0AbJD9AH2s/gCBsP0Ac5v+AFt6/QAtPv0AAAD9AAAA/gAAAP4AAAD+A" - "AAA/wAAAIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAWgAAAOIAAAD/AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AA" - "AD+AAAA/gAAAP8AAAD/AAAAmQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAIgAAADRAAAA/wAAA" - "P8AAAD/AAAA/wAAAP8AAAD/AAAA5QAAAJoAAABWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAIAAAACQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///gAf///////4AAAAD/////wAAAAP////" - "/AAAAB/////+AAAAH/////4AAAA//////gAAAD/////8AAAAH/////wAAAAP////+AAAAA/////4AAA" - "AD/////gAAAAP////+AAAAA/////4AAAAD/////gAAAAP////+AAAAA/////4AAAAB/////gAAAAD//" - "//+AAAAAP////wAAAAA////+AAAAAD////wAAAAAP///8AAAAAA////gAAAAAB///8AAAAAAH///gAA" - "AAAAf//+AAAAAAA///4AAAAAAD///4AAAAAAP///wAAAAAAf///wAAAAAD////gAAAAAP////gAAAAB" - "/////AAAAAP////+AAAAD/////wAAAAf////+AAAAB/////4AAAAD/////AAAAAP////8AAAAA/////" - "wAAAAB////+AAAAAH////4AAAAAf////gAAAAA////+AAAAAD////4AAAAAP////gAAAAA////+AAAA" - "AD////4AAAAAf////gAAAAB////+AAAAAH////8AAAAAf////wAAAAD/////gAAAAP////+AAAAB///" - "//8AAAAH/////wAAAA//////gAAAH//////AAAA//////+AAAH//////+AAA///////+AAP///////+" - "AH//////////////8="; - - const char HTTP_COMMAND_TUNNELS[] = "tunnels"; - const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels"; - const char HTTP_COMMAND_TRANSPORTS[] = "transports"; - const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; - const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; - const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; - const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; - const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; - const char HTTP_COMMAND_SAM_SESSIONS[] = "sam_sessions"; - const char HTTP_COMMAND_SAM_SESSION[] = "sam_session"; - const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; - - namespace misc_strings - { - - const char name_value_separator[] = { ':', ' ' }; - const char crlf[] = { '\r', '\n' }; - - } // namespace misc_strings - - std::vector HTTPConnection::reply::to_buffers(int status) - { - std::vector buffers; - if (headers.size () > 0) - { - buffers.push_back(boost::asio::buffer("HTTP/1.1 ", 9)); - buffers.push_back(boost::asio::buffer(boost::lexical_cast(status), 3)); - buffers.push_back(boost::asio::buffer(" ", 1)); - std::string status_string; - switch (status) - { - case 105: status_string = "Name Not Resolved"; break; - case 200: status_string = "OK"; break; - case 400: status_string = "Bad Request"; break; - case 404: status_string = "Not Found"; break; - case 408: status_string = "Request Timeout"; break; - case 500: status_string = "Internal Server Error"; break; - case 502: status_string = "Bad Gateway"; break; - case 503: status_string = "Not Implemented"; break; - case 504: status_string = "Gateway Timeout"; break; - } - buffers.push_back(boost::asio::buffer(status_string, status_string.size())); - buffers.push_back(boost::asio::buffer(misc_strings::crlf)); - for (std::size_t i = 0; i < headers.size(); ++i) - { - header& h = headers[i]; - buffers.push_back(boost::asio::buffer(h.name)); - buffers.push_back(boost::asio::buffer(misc_strings::name_value_separator)); - buffers.push_back(boost::asio::buffer(h.value)); - buffers.push_back(boost::asio::buffer(misc_strings::crlf)); - } - buffers.push_back(boost::asio::buffer(misc_strings::crlf)); - } - buffers.push_back(boost::asio::buffer(content)); - return buffers; - } - - void HTTPConnection::Terminate () - { - m_Socket->close (); - } - - void HTTPConnection::Receive () - { - m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), - std::bind(&HTTPConnection::HandleReceive, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); - } - - void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) - { - if(!ecode) { - m_Buffer[bytes_transferred] = 0; - m_BufferLen = bytes_transferred; - RunRequest(); - } - else if (ecode != boost::asio::error::operation_aborted) - Terminate (); - } - - void HTTPConnection::RunRequest () - { - auto address = ExtractAddress (); - if (address.length () > 1 && address[1] != '?') // not just '/' or '/?' - return; // TODO: error handling - - HandleRequest (address); - } - - std::string HTTPConnection::ExtractAddress () - { - char * get = strstr (m_Buffer, "GET"); - if (get) - { - char * http = strstr (get, "HTTP"); - if (http) - return std::string (get + 4, http - get - 5); - } - return ""; - } - - void HTTPConnection::ExtractParams (const std::string& str, std::map& params) - { - if (str[0] != '&') return; - size_t pos = 1, end; - do - { - end = str.find ('&', pos); - std::string param = str.substr (pos, end - pos); - LogPrint (param); - size_t e = param.find ('='); - if (e != std::string::npos) - params[param.substr(0, e)] = param.substr(e+1); - pos = end + 1; - } - while (end != std::string::npos); - } - - void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - boost::system::error_code ignored_ec; - m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - Terminate (); - } - } - - void HTTPConnection::HandleRequest (const std::string& address) - { - std::stringstream s; - // Html5 head start - s << "\n"; // TODO: Add support for locale. - s << ""; // TODO: Find something to parse html/template system. This is horrible. - s << "Purple I2P " << VERSION " Webconsole"; - // Head end - if (address.length () > 1) - HandleCommand (address.substr (2), s); - else - FillContent (s); - s << ""; - SendReply (s.str ()); - } - - void HTTPConnection::FillContent (std::stringstream& s) - { - s << "

Welcome to the Webconsole!


"; - s << "Uptime: " << boost::posix_time::to_simple_string ( - boost::posix_time::time_duration (boost::posix_time::seconds ( - i2p::context.GetUptime ()))) << "
"; - s << "Status: "; - switch (i2p::context.GetStatus ()) - { - case eRouterStatusOK: s << "OK"; break; - case eRouterStatusTesting: s << "Testing"; break; - case eRouterStatusFirewalled: s << "Firewalled"; break; - default: s << "Unknown"; - } - s << "
"; - s << "Tunnel creation success rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%
"; - s << "Received: " << i2p::transport::transports.GetTotalReceivedBytes ()/1000 << "K"; - s << " (" << i2p::transport::transports.GetInBandwidth () <<" Bps)
"; - s << "Sent: " << i2p::transport::transports.GetTotalSentBytes ()/1000 << "K"; - s << " (" << i2p::transport::transports.GetOutBandwidth () <<" Bps)
"; - s << "Data path: " << i2p::util::filesystem::GetDataDir().string() << "

"; - s << "Our external address:" << "
" ; - for (auto& address : i2p::context.GetRouterInfo().GetAddresses()) - { - switch (address.transportStyle) - { - case i2p::data::RouterInfo::eTransportNTCP: - if (address.host.is_v6 ()) - s << "NTCP6  "; - else - s << "NTCP  "; - break; - case i2p::data::RouterInfo::eTransportSSU: - if (address.host.is_v6 ()) - s << "SSU6     "; - else - s << "SSU     "; - break; - default: - s << "Unknown  "; - } - s << address.host.to_string() << ":" << address.port << "
"; - } - s << "
Routers: " << i2p::data::netdb.GetNumRouters () << " "; - s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; - s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
"; - - s << "
Local destinations"; - s << "
Tunnels"; - s << "
Transit tunnels"; - s << "
Transports"; - if (i2p::client::context.GetSAMBridge ()) - s << "
SAM sessions"; - s << "
"; - - if (i2p::context.AcceptsTunnels ()) - s << "
Stop accepting tunnels
"; - else - s << "
Start accepting tunnels
"; - } + m_Socket->close(); +} - void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s) - { - size_t paramsPos = command.find('&'); - std::string cmd = command.substr (0, paramsPos); - if (cmd == HTTP_COMMAND_TRANSPORTS) - ShowTransports (s); - else if (cmd == HTTP_COMMAND_TUNNELS) - ShowTunnels (s); - else if (cmd == HTTP_COMMAND_TRANSIT_TUNNELS) - ShowTransitTunnels (s); - else if (cmd == HTTP_COMMAND_START_ACCEPTING_TUNNELS) - StartAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) - StopAcceptingTunnels (s); - else if (cmd == HTTP_COMMAND_LOCAL_DESTINATIONS) - ShowLocalDestinations (s); - else if (cmd == HTTP_COMMAND_LOCAL_DESTINATION) - { - std::map params; - ExtractParams (command.substr (paramsPos), params); - auto b32 = params[HTTP_PARAM_BASE32_ADDRESS]; - ShowLocalDestination (b32, s); - } - else if (cmd == HTTP_COMMAND_SAM_SESSIONS) - ShowSAMSessions (s); - else if (cmd == HTTP_COMMAND_SAM_SESSION) - { - std::map params; - ExtractParams (command.substr (paramsPos), params); - auto id = params[HTTP_PARAM_SAM_SESSION_ID]; - ShowSAMSession (id, s); - } - } +void HTTPConnection::Receive() +{ + m_Socket->async_read_some( + boost::asio::buffer(m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), std::bind( + &HTTPConnection::HandleReceive, shared_from_this(), + std::placeholders::_1, std::placeholders::_2 + ) + ); +} - void HTTPConnection::ShowTransports (std::stringstream& s) - { - auto ntcpServer = i2p::transport::transports.GetNTCPServer (); - if (ntcpServer) - { - s << "NTCP
"; - for (auto it: ntcpServer->GetNTCPSessions ()) - { - if (it.second && it.second->IsEstablished ()) - { - // incoming connection doesn't have remote RI - auto outgoing = it.second->GetRemoteRouter (); - if (outgoing) s << "-->"; - s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string (); - if (!outgoing) s << "-->"; - s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - s << "
"; - } - s << std::endl; - } - } - auto ssuServer = i2p::transport::transports.GetSSUServer (); - if (ssuServer) - { - s << "
SSU
"; - for (auto it: ssuServer->GetSessions ()) - { - // incoming connections don't have remote router - auto outgoing = it.second->GetRemoteRouter (); - auto endpoint = it.second->GetRemoteEndpoint (); - if (outgoing) s << "-->"; - s << endpoint.address ().to_string () << ":" << endpoint.port (); - if (!outgoing) s << "-->"; - s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - if (it.second->GetRelayTag ()) - s << " [itag:" << it.second->GetRelayTag () << "]"; - s << "
"; - s << std::endl; - } - } - } - - void HTTPConnection::ShowTunnels (std::stringstream& s) - { - s << "Queue size:" << i2p::tunnel::tunnels.GetQueueSize () << "
"; +void HTTPConnection::HandleReceive(const boost::system::error_code& e, std::size_t nb_bytes) +{ + if(!e) { + m_Buffer[nb_bytes] = 0; + m_BufferLen = nb_bytes; + RunRequest(); + } else if(e != boost::asio::error::operation_aborted) + Terminate(); +} - for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) - { - it->GetTunnelConfig ()->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << " " << (int)it->GetNumSentBytes () << "
"; - s << std::endl; - } +void HTTPConnection::RunRequest() +{ + m_Request = i2p::util::http::Request(std::string(m_Buffer, m_Buffer + m_BufferLen)); + HandleRequest(); +} - for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) - { - it.second->GetTunnelConfig ()->Print (s); - auto state = it.second->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << " " << (int)it.second->GetNumReceivedBytes () << "
"; - s << std::endl; - } +void HTTPConnection::ExtractParams(const std::string& str, std::map& params) +{ + if(str[0] != '&') return; + size_t pos = 1, end; + do + { + end = str.find('&', pos); + std::string param = str.substr(pos, end - pos); + LogPrint(param); + size_t e = param.find('='); + if(e != std::string::npos) + params[param.substr(0, e)] = param.substr(e+1); + pos = end + 1; } + while(end != std::string::npos); +} - void HTTPConnection::ShowTransitTunnels (std::stringstream& s) - { - for (auto it: i2p::tunnel::tunnels.GetTransitTunnels ()) - { - if (dynamic_cast(it.second)) - s << it.second->GetTunnelID () << "-->"; - else if (dynamic_cast(it.second)) - s << "-->" << it.second->GetTunnelID (); - else - s << "-->" << it.second->GetTunnelID () << "-->"; - s << " " << it.second->GetNumTransmittedBytes () << "
"; - } +void HTTPConnection::HandleWriteReply(const boost::system::error_code& e) +{ + if(e != boost::asio::error::operation_aborted) { + boost::system::error_code ignored_ec; + m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + Terminate(); } +} - void HTTPConnection::ShowLocalDestinations (std::stringstream& s) - { - for (auto& it: i2p::client::context.GetDestinations ()) - { - auto ident = it.second->GetIdentHash ();; - s << ""; - s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; - } - } - - void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s) - { - i2p::data::IdentHash ident; - ident.FromBase32 (b32); - auto dest = i2p::client::context.FindLocalDestination (ident); - if (dest) - { - s << "Base64:
" << dest->GetIdentity ().ToBase64 () << "

"; - s << "LeaseSets: " << dest->GetNumRemoteLeaseSets () << "
"; - auto pool = dest->GetTunnelPool (); - if (pool) - { - s << "Tunnels:
"; - for (auto it: pool->GetOutboundTunnels ()) - { - it->GetTunnelConfig ()->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << "
" << std::endl; - } - for (auto it: pool->GetInboundTunnels ()) - { - it->GetTunnelConfig ()->Print (s); - auto state = it->GetState (); - if (state == i2p::tunnel::eTunnelStateFailed) - s << " " << "Failed"; - else if (state == i2p::tunnel::eTunnelStateExpiring) - s << " " << "Exp"; - s << "
" << std::endl; - } - } - s << "
Streams:
"; - for (auto it: dest->GetStreamingDestination ()->GetStreams ()) - { - s << it.first << "->" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetRemoteIdentity ()) << " "; - s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]"; - s << "[buf:" << it.second->GetSendBufferSize () << "]"; - s << "[RTT:" << it.second->GetRTT () << "]"; - s << "[Window:" << it.second->GetWindowSize () << "]"; - s << "[Status:" << (int)it.second->GetStatus () << "]"; - s << "
"<< std::endl; - } - } - } +void HTTPConnection::HandleRequest() +{ + boost::system::error_code e; - void HTTPConnection::ShowSAMSessions (std::stringstream& s) - { - auto sam = i2p::client::context.GetSAMBridge (); - if (sam) - { - for (auto& it: sam->GetSessions ()) - { - s << ""; - s << it.first << "
" << std::endl; - } - } - } + std::string uri = m_Request.getUri(); + if(uri == "/") + uri = "index.html"; - void HTTPConnection::ShowSAMSession (const std::string& id, std::stringstream& s) - { - auto sam = i2p::client::context.GetSAMBridge (); - if (sam) - { - auto session = sam->FindSession (id); - if (session) - { - auto& ident = session->localDestination->GetIdentHash(); - s << ""; - s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
" << std::endl; - s << "Streams:
"; - for (auto it: session->sockets) - { - switch (it->GetSocketType ()) - { - case i2p::client::eSAMSocketTypeSession: - s << "session"; - break; - case i2p::client::eSAMSocketTypeStream: - s << "stream"; - break; - case i2p::client::eSAMSocketTypeAcceptor: - s << "acceptor"; - break; - default: - s << "unknown"; - } - s << " [" << it->GetSocket ().remote_endpoint() << "]"; - s << "
" << std::endl; - } - } - } - } + // Use cannonical to avoid .. or . in path + const std::string address = boost::filesystem::canonical( + i2p::util::filesystem::GetWebuiDataDir() / uri, e + ).string(); - void HTTPConnection::StartAcceptingTunnels (std::stringstream& s) - { - i2p::context.SetAcceptsTunnels (true); - s << "Accepting tunnels started" << std::endl; - } + std::ifstream ifs(address); + if(e || !ifs || !isAllowed(address)) { + m_Reply = i2p::util::http::Response(404, ""); + return SendReply(); + } + + std::string str; + ifs.seekg(0, ifs.end); + str.resize(ifs.tellg()); + ifs.seekg(0, ifs.beg); + ifs.read(&str[0], str.size()); + ifs.close(); + + m_Reply = i2p::util::http::Response(200, str); + SendReply(); +} - void HTTPConnection::StopAcceptingTunnels (std::stringstream& s) - { - i2p::context.SetAcceptsTunnels (false); - s << "Accepting tunnels stopped" << std::endl; - } +bool HTTPConnection::isAllowed(const std::string& address) +{ + const std::size_t pos_dot = address.find_last_of('.'); + const std::size_t pos_slash = address.find_last_of('/'); + if(pos_dot == std::string::npos || pos_dot == address.size() - 1) + return false; + if(pos_slash != std::string::npos && pos_dot < pos_slash) + return false; + return true; +} - void HTTPConnection::SendReply (const std::string& content, int status) - { - m_Reply.content = content; - m_Reply.headers.resize(3); - // we need the date header to be compliant with HTTP 1.1 - std::time_t time_now = std::time(nullptr); - char time_buff[128]; - if ( std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)) ) { - m_Reply.headers[0].name = "Date"; - m_Reply.headers[0].value = std::string(time_buff); - m_Reply.headers[1].name = "Content-Length"; - m_Reply.headers[1].value = boost::lexical_cast(m_Reply.content.size()); - m_Reply.headers[2].name = "Content-Type"; - m_Reply.headers[2].value = "text/html"; - } - boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), - std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1)); - } +void HTTPConnection::SendReply() +{ + // we need the date header to be compliant with HTTP 1.1 + std::time_t time_now = std::time(nullptr); + char time_buff[128]; + if(std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)) ) { + m_Reply.setHeader("Date", std::string(time_buff)); + m_Reply.setContentLength(); + m_Reply.setHeader("Content-Type", "text/html"); + } + boost::asio::async_write( + *m_Socket, boost::asio::buffer(m_Reply.toString()), + std::bind(&HTTPConnection::HandleWriteReply, shared_from_this(), std::placeholders::_1) + ); +} - HTTPServer::HTTPServer (const std::string& address, int port): - m_Thread (nullptr), m_Work (m_Service), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)), - m_NewSocket (nullptr) - { +HTTPServer::HTTPServer(const std::string& address, int port): + m_Thread(nullptr), m_Work(m_Service), + m_Acceptor(m_Service, boost::asio::ip::tcp::endpoint( + boost::asio::ip::address::from_string(address), port) + ), m_NewSocket(nullptr) +{ - } +} - HTTPServer::~HTTPServer () - { - Stop (); - } +HTTPServer::~HTTPServer() +{ + Stop(); +} - void HTTPServer::Start () - { - m_Thread = new std::thread (std::bind (&HTTPServer::Run, this)); - m_Acceptor.listen (); - Accept (); - } +void HTTPServer::Start() +{ + m_Thread = new std::thread(std::bind(&HTTPServer::Run, this)); + m_Acceptor.listen(); + Accept(); +} - void HTTPServer::Stop () +void HTTPServer::Stop() +{ + m_Acceptor.close(); + m_Service.stop(); + if(m_Thread) { - m_Acceptor.close(); - m_Service.stop (); - if (m_Thread) - { - m_Thread->join (); - delete m_Thread; - m_Thread = nullptr; - } + m_Thread->join(); + delete m_Thread; + m_Thread = nullptr; } +} - void HTTPServer::Run () - { - m_Service.run (); - } +void HTTPServer::Run() +{ + m_Service.run(); +} - void HTTPServer::Accept () - { - m_NewSocket = new boost::asio::ip::tcp::socket (m_Service); - m_Acceptor.async_accept (*m_NewSocket, boost::bind (&HTTPServer::HandleAccept, this, - boost::asio::placeholders::error)); - } +void HTTPServer::Accept() +{ + m_NewSocket = new boost::asio::ip::tcp::socket(m_Service); + m_Acceptor.async_accept(*m_NewSocket, boost::bind(&HTTPServer::HandleAccept, this, + boost::asio::placeholders::error)); +} - void HTTPServer::HandleAccept(const boost::system::error_code& ecode) +void HTTPServer::HandleAccept(const boost::system::error_code& ecode) +{ + if(!ecode) { - if (!ecode) - { - CreateConnection(m_NewSocket); - Accept (); - } + CreateConnection(m_NewSocket); + Accept(); } +} - void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) - { - auto conn = std::make_shared (m_NewSocket); - conn->Receive (); - } +void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) +{ + auto conn = std::make_shared(m_NewSocket); + conn->Receive(); +} } } diff --git a/client/HTTPServer.h b/client/HTTPServer.h index dcb74b3e..5bf253f2 100644 --- a/client/HTTPServer.h +++ b/client/HTTPServer.h @@ -6,119 +6,71 @@ #include #include #include +#include "util/HTTP.h" -namespace i2p -{ -namespace util -{ - const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; - const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds - class HTTPConnection: public std::enable_shared_from_this - { - protected: - - struct header - { - std::string name; - std::string value; - }; - - struct request - { - std::string method; - std::string uri; - std::string host; - int port; - int http_version_major; - int http_version_minor; - std::vector
headers; - }; - - struct reply - { - std::vector
headers; - std::string content; - - std::vector to_buffers (int status); - }; - - public: - - HTTPConnection (boost::asio::ip::tcp::socket * socket): - m_Socket (socket), m_Timer (socket->get_io_service ()), - m_BufferLen (0) {}; - ~HTTPConnection() { delete m_Socket; } - void Receive (); - - private: - - void Terminate (); - void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void HandleWriteReply(const boost::system::error_code& ecode); - void SendReply (const std::string& content, int status = 200); - - void HandleRequest (const std::string& address); - void HandleCommand (const std::string& command, std::stringstream& s); - void ShowTransports (std::stringstream& s); - void ShowTunnels (std::stringstream& s); - void ShowTransitTunnels (std::stringstream& s); - void ShowLocalDestinations (std::stringstream& s); - void ShowLocalDestination (const std::string& b32, std::stringstream& s); - void ShowSAMSessions (std::stringstream& s); - void ShowSAMSession (const std::string& id, std::stringstream& s); - void StartAcceptingTunnels (std::stringstream& s); - void StopAcceptingTunnels (std::stringstream& s); - void FillContent (std::stringstream& s); - std::string ExtractAddress (); - void ExtractParams (const std::string& str, std::map& params); - - - protected: - - boost::asio::ip::tcp::socket * m_Socket; - boost::asio::deadline_timer m_Timer; - char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; - size_t m_BufferLen; - request m_Request; - reply m_Reply; - - protected: - - virtual void RunRequest (); - - public: - - static const std::string itoopieImage; - static const std::string itoopieFavicon; - }; +namespace i2p { +namespace util { - class HTTPServer - { - public: +const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; +const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds - HTTPServer (const std::string& address, int port); - virtual ~HTTPServer (); +class HTTPConnection: public std::enable_shared_from_this { +public: - void Start (); - void Stop (); + HTTPConnection(boost::asio::ip::tcp::socket * socket) + : m_Socket(socket), m_Timer(socket->get_io_service()), + m_BufferLen(0) {}; + ~HTTPConnection() { delete m_Socket; } + void Receive(); + +private: - private: + void Terminate(); + void HandleReceive(const boost::system::error_code& ecode, std::size_t bytes_transferred); + void RunRequest(); + void HandleWriteReply(const boost::system::error_code& ecode); + void SendReply(); - void Run (); - void Accept (); - void HandleAccept(const boost::system::error_code& ecode); - - private: + void HandleRequest(); + void ExtractParams(const std::string& str, std::map& params); + + bool isAllowed(const std::string& address); +private: + boost::asio::ip::tcp::socket* m_Socket; + boost::asio::deadline_timer m_Timer; + char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; + char m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; + size_t m_BufferLen; + util::http::Request m_Request; + util::http::Response m_Reply; +}; + +class HTTPServer { +public: + + HTTPServer(const std::string& address, int port); + virtual ~HTTPServer(); + + void Start(); + void Stop(); + +private: + + void Run(); + void Accept(); + void HandleAccept(const boost::system::error_code& ecode); + +private: - std::thread * m_Thread; - boost::asio::io_service m_Service; - boost::asio::io_service::work m_Work; - boost::asio::ip::tcp::acceptor m_Acceptor; - boost::asio::ip::tcp::socket * m_NewSocket; + std::thread * m_Thread; + boost::asio::io_service m_Service; + boost::asio::io_service::work m_Work; + boost::asio::ip::tcp::acceptor m_Acceptor; + boost::asio::ip::tcp::socket * m_NewSocket; - protected: - virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket); - }; +protected: + virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket); +}; } } diff --git a/core/util/HTTP.cpp b/core/util/HTTP.cpp index db740f55..28c5236d 100644 --- a/core/util/HTTP.cpp +++ b/core/util/HTTP.cpp @@ -55,8 +55,8 @@ std::string Request::getHeader(const std::string& name) const return headers.at(name); } -Response::Response(int status) - : status(status), headers() +Response::Response(int status, const std::string& content) + : status(status), content(content), headers() { } @@ -72,7 +72,7 @@ std::string Response::toString() const ss << "HTTP/1.1 " << status << ' ' << getStatusMessage() << "\r\n"; for(auto& pair : headers) ss << pair.first << ": " << pair.second << "\r\n"; - ss << "\r\n"; + ss << "\r\n" << content; return ss.str(); } @@ -99,6 +99,12 @@ std::string Response::getStatusMessage() const return std::string(); } } + +void Response::setContentLength() +{ + setHeader("Content-Length", std::to_string(content.size())); +} + } } } diff --git a/core/util/HTTP.h b/core/util/HTTP.h index 252b1533..b587dd30 100644 --- a/core/util/HTTP.h +++ b/core/util/HTTP.h @@ -14,9 +14,9 @@ class Request { void parseHeaderLine(const std::string& line); public: - Request(const std::string& data); + Request() = default; - Request(); + Request(const std::string& data); std::string getMethod() const; @@ -41,8 +41,9 @@ private: class Response { public: + Response() = default; - Response(int status); + Response(int status, const std::string& content = ""); /** * @note overrides existing header values with the same name @@ -57,8 +58,11 @@ public: */ std::string getStatusMessage() const; + void setContentLength(); + private: int status; + std::string content; std::map headers; }; diff --git a/tests/Utility.cpp b/tests/Utility.cpp index ec285b4e..07d77c53 100644 --- a/tests/Utility.cpp +++ b/tests/Utility.cpp @@ -125,6 +125,7 @@ BOOST_AUTO_TEST_CASE(HTTPResponseStatusMessage) BOOST_CHECK_EQUAL(Response(502).getStatusMessage(), "Not Implemented"); BOOST_CHECK_EQUAL(Response(504).getStatusMessage(), "Gateway Timeout"); } + BOOST_AUTO_TEST_CASE(WriteHTTPResponse) { Response rsp(200); @@ -136,5 +137,16 @@ BOOST_AUTO_TEST_CASE(WriteHTTPResponse) ); } +BOOST_AUTO_TEST_CASE(WriteHTTPResponseWithContent) +{ + Response rsp(200, "Test content."); + rsp.setHeader("Connection", "close"); + BOOST_CHECK_EQUAL( + rsp.toString(), + "HTTP/1.1 200 OK\r\n" + "Connection: close\r\n\r\n" + "Test content." + ); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/webui/index.html b/webui/index.html index 3d98ba3d..8d82aeb0 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1 +1,11 @@ -Nothing here yet. + + + +Purple I2P 0.10.0 Webconsole + + + + +

Nothing here yet.

+ +