Last active
November 14, 2022 02:14
-
-
Save CyberShadow/911864f3b0882ec8e8e9bbf75513eef6 to your computer and use it in GitHub Desktop.
favicon_ua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ProxyPassMatch "^/(favicon\.ico)$" http://127.2.146.142:14471/$REAL_UPSTREAM/$1 nocanon | |
import std.algorithm.searching; | |
import std.stdio : stderr; | |
import std.string : split, join; | |
import ae.net.asockets; | |
import ae.net.http.client; | |
import ae.net.http.responseex; | |
import ae.net.http.server; | |
import ae.sys.cmd; | |
import ae.sys.imagemagick; | |
import ae.utils.graphics.color; | |
import ae.utils.graphics.image; | |
class MyClient : HttpClient | |
{ | |
string realHost; ushort realPort = 81; | |
override void sendRequest(HttpRequest request) | |
{ | |
sendRawRequest(request); | |
} | |
override void request(HttpRequest request) | |
{ | |
//debug writefln("New HTTP request: %s", request.url); | |
currentRequest = request; | |
currentResponse = null; | |
conn.handleReadData = &onNewResponse; | |
expect = 0; | |
if (conn.state != ConnectionState.disconnected) | |
{ | |
assert(conn.state == ConnectionState.connected, "Attempting a HTTP request on a %s connection".format(conn.state)); | |
assert(keepAlive, "Attempting a second HTTP request on a connected non-keepalive connection"); | |
sendRequest(request); | |
} | |
else | |
{ | |
connector.connect(realHost, realPort); | |
} | |
} | |
} | |
void main() | |
{ | |
auto s = new HttpServer; | |
s.handleRequest = (HttpRequest request, HttpServerConnection conn) { | |
stderr.writeln(request.url, " - Request received"); | |
auto client = new MyClient; | |
client.realHost = request.resource.split("/")[1]; | |
request.resource = "/" ~ request.resource.split("/")[2..$].join("/"); | |
client.handleResponse = | |
(HttpResponse response, string /*disconnectReason*/) | |
{ | |
stderr.writeln(request.url, " - Response obtained: ", response.headers.get("Content-Type", null)); | |
if (response.headers.get("Content-Type", null).startsWith("image/")) | |
{ | |
stderr.writeln(request.url, " - Processing image"); | |
try | |
{ | |
auto data = response.getContent(); | |
auto image = data.contents.parseViaIMConvert!BGRA(mimeTypeToIMFormat(response.headers["Content-Type"])); | |
foreach (y; 0 .. image.h) | |
foreach (ref cell; image.scanline(y)) | |
foreach (ref c; cell) | |
{ | |
auto g_100 = ( | |
c.r * 7 + | |
c.g * 72 + | |
c.b * 21 | |
); | |
// https://en.wikipedia.org/wiki/Flag_of_Ukraine#Design | |
if (y < image.h / 2) | |
{ | |
c.r = 0; | |
// c.g = cast(ubyte)(g_100 * 87 / (255 * 100)); | |
// c.b = cast(ubyte)(g_100 * 183 / (255 * 100)); | |
c.g = cast(ubyte)(g_100 * 128 / (255 * 100)); | |
c.b = cast(ubyte)(g_100 * 255 / (255 * 100)); | |
} | |
else | |
{ | |
c.r = cast(ubyte)(g_100 * 255 / (255 * 100)); | |
c.g = cast(ubyte)(g_100 * 215 / (255 * 100)); | |
c.b = 0; | |
} | |
} | |
response.headers["Content-Type"] = "image/png"; | |
response.headers.remove("Transfer-Encoding"); | |
response.headers.remove("Content-Encoding"); | |
response.headers.remove("Content-Length"); | |
response.data = DataVec(Data(image.colorMap!(c => RGBA(c.r, c.g, c.b, c.a)).toPNG)); | |
foreach (name, value; response.headers) | |
stderr.writeln(" - ", name, ": ", value); | |
stderr.writeln(request.url, " - Painted successfully"); | |
} | |
catch (Exception e) | |
{ | |
stderr.writeln(request.url, " - ", e); | |
// oh well | |
} | |
} | |
if (!response.status) | |
response.setStatus(HttpStatusCode.BadGateway); | |
conn.sendResponse(response); | |
}; | |
client.request(request); // TODO sendRawRequest | |
}; | |
s.listen(14471, "127.2.146.142"); | |
stderr.writeln("Listening on ", s.localAddresses); | |
socketManager.loop(); | |
} | |
string mimeTypeToIMFormat(string mimeType) | |
{ | |
mimeType = mimeType.findSplit(";")[0]; | |
switch (mimeType) | |
{ | |
case "image/png": | |
return "png"; | |
case "image/jpeg": | |
case "image/jpg": | |
return "jpeg"; | |
case "image/vnd.microsoft.icon": | |
return "ico"; | |
default: | |
throw new Exception("Unknown MIME type: " ~ mimeType); | |
} | |
} | |
auto parseViaIMConvert(COLOR)(const(void)[] data, string format) | |
{ | |
string[] convertFlags; | |
static if (is(COLOR : BGR)) | |
{ | |
// convertFlags ~= ["-colorspace", "rgb"]; | |
// convertFlags ~= ["-depth", "24"]; | |
convertFlags ~= ["-type", "TrueColor"]; | |
convertFlags ~= ["-alpha", "off"]; | |
} | |
else | |
static if (is(COLOR : BGRA)) | |
{ | |
convertFlags ~= ["-type", "TrueColorAlpha"]; | |
convertFlags ~= ["-alpha", "on"]; | |
} | |
return data | |
.pipe(["convert".imageMagickBinary()] ~ convertFlags ~ [format ~ ":-[0]", "bmp:-"]) | |
.viewBMP!COLOR(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment