{"id":16243301,"url":"https://github.com/svrooij/unobtanium-web-proxy","last_synced_at":"2025-03-19T17:32:08.931Z","repository":{"id":241505373,"uuid":"806697080","full_name":"svrooij/unobtanium-web-proxy","owner":"svrooij","description":"HTTP(S) proxy server in C#.","archived":false,"fork":false,"pushed_at":"2024-09-11T14:31:25.000Z","size":8849,"stargazers_count":38,"open_issues_count":9,"forks_count":7,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2025-03-17T09:45:10.550Z","etag":null,"topics":["dotnet","titanium-web-proxy","web-proxy-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"justcoding121/titanium-web-proxy","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/svrooij.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"svrooij"}},"created_at":"2024-05-27T17:52:14.000Z","updated_at":"2025-03-12T02:10:39.000Z","dependencies_parsed_at":"2024-06-18T00:10:53.928Z","dependency_job_id":"33a7d189-1cc1-4d54-8b5a-9cf0490e1407","html_url":"https://github.com/svrooij/unobtanium-web-proxy","commit_stats":null,"previous_names":["svrooij/titanium-web-proxy","svrooij/unobtanium-web-proxy"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svrooij%2Funobtanium-web-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svrooij%2Funobtanium-web-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svrooij%2Funobtanium-web-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/svrooij%2Funobtanium-web-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/svrooij","download_url":"https://codeload.github.com/svrooij/unobtanium-web-proxy/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244473956,"owners_count":20458560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","titanium-web-proxy","web-proxy-server"],"created_at":"2024-10-10T14:14:27.221Z","updated_at":"2025-03-19T17:32:08.445Z","avatar_url":"https://github.com/svrooij.png","language":"C#","readme":"# Unobtanium Web Proxy\n\nA lightweight HTTP(S) proxy server written in C# `NET8.0`.\n\n[![Unobtanium web proxy][badge_twp-repo]][link_twp-repo]\n[![nuget][badge_nuget]][link_nuget]\n[![github issues][badge_issues]][link_issues]\n[![License][badle_license]][link_license]\n[![Build status][badge_twp_build]][link_build]\n[![Support me on Github][badge_sponsor]][link_sponsor]\n\nReport bugs or raise issues here.\n\n## Project reboot\n\n[![Unobtanium web proxy][badge_twp-repo]][link_twp-repo]\n\nThis project is a reboot of the original [Titanium-Web-Proxy](https://github.com/justcoding121/titanium-web-proxy) project. The original project was last updated two years ago, has been archived by the author on July 9th 2023 and has been inactive since then. This project aims to continue the development of the original project and provide a stable and reliable proxy server library for .NET developers.\n\n[Announcement](https://github.com/svrooij/titanium-web-proxy/discussions/2) [Reboot discussion](https://github.com/svrooij/titanium-web-proxy/discussions/7) [Issues](https://github.com/svrooij/titanium-web-proxy/issues?q=is%3Aissue+is%3Aopen+label%3Areboot)\n\n### Reboot focus\n\n* `net8.0` only (no support for older versions of .NET!)\n* Support for `ILogger` [See #4](https://github.com/svrooij/titanium-web-proxy/issues/4)\n* Support for diagnostic events using `ActivitySource` and `Activity` [See #3](https://github.com/svrooij/titanium-web-proxy/issues/3)\n* Using the latest .NET features like `Span\u003cT\u003e` and `Memory\u003cT\u003e` to improve performance\n* Update dependencies to the latest versions\n* `TLS 1.2` and `TLS 1.3` only support\n* Event-handlers with `HttpRequestMessage` and `HttpResponseMessage`, to greatly improve the portability of the library [See #6](https://github.com/svrooij/titanium-web-proxy/issues/6)\n* `HttpClient` as the default client, and using the IHttpClientFactory to handle pooling of the clients\n* Testing, testing, testing!\n\n## Features\n\n* ~~[API Documentation](https://justcoding121.github.io/titanium-web-proxy/docs/api/Titanium.Web.Proxy.ProxyServer.html)~~\n* ~~[Wiki \u0026 Contribution guidelines](https://github.com/justcoding121/Titanium-Web-Proxy/wiki)~~\n* Multithreaded and asynchronous proxy employing server connection pooling, certificate cache, and buffer pooling\n* View, modify, redirect and block requests or responses\n* Supports mutual SSL authentication, proxy authentication \u0026 automatic upstream proxy detection\n* Supports kerberos, NTLM authentication over HTTP protocols on windows domain controlled networks\n* SOCKS4/5 Proxy support\n\n## Installation\n\nPackage on [NuGet][link_nuget], `Unobtanium.Web.Proxy` will be a partial drop-in replacement for `Titanium.Web.Proxy`, if you're on `NET8.0 or higher`.\n\n```bash\ndotnet add package Unobtanium.Web.Proxy\n```\n\nSupports\n\n* `.NET 8.0` and above\n\nAs stated [above](#project-reboot), this project is a reboot of the original project. Expect things to change, everything marked as `obsolete` in the original project will be removed in this project. And until this is `v1.0.0`, expect [breaking changes](#reboot-focus).\n\n## Collaborators\n\nThe owner of this project, [justcoding121](https://github.com/justcoding121), is considered to be inactive from this project due to his busy work schedule. See [project reboot](#project-reboot) for more information.\n\nPrevious contributors:\n\n* [justcoding121](https://github.com/justcoding121) *owner*\n* [honfika](https://github.com/honfika)\n\nCurrent contributors:\n\n* [svrooij](https://github.com/svrooij)\n\nYou contributions are more then welcome! Let's make this project great again!\n\n## Development environment\n\nSince this is a `dotnet` project I would suggest to use `Visual Studio 2022` or `Visual Studio Code` as your development environment. The project is set up to use the `dotnet` CLI, so you can also use that to build and run the project.\n\n## Usage\n\nRefer the `Unobtanium.Web.Proxy` in your project and check one of the [example projects](https://github.com/svrooij/titanium-web-proxy/tree/develop/examples).\n\nSetup HTTP proxy:\n\n```csharp\nusing Titanium.Web.Proxy;\n...\nvar proxyServer = new ProxyServer();\n\n// locally trust root certificate used by this proxy \nproxyServer.CertificateManager.TrustRootCertificate(true);\n\n// optionally set the Certificate Engine\n// Under Mono only BouncyCastle will be supported\n//proxyServer.CertificateManager.CertificateEngine = Network.CertificateEngine.BouncyCastle;\n\nproxyServer.BeforeRequest += OnRequest;\nproxyServer.BeforeResponse += OnResponse;\nproxyServer.ServerCertificateValidationCallback += OnCertificateValidation;\nproxyServer.ClientCertificateSelectionCallback += OnCertificateSelection;\n\n\nvar explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true)\n{\n    // Use self-issued generic certificate on all https requests\n    // Optimizes performance by not creating a certificate for each https-enabled domain\n    // Useful when certificate trust is not required by proxy clients\n   //GenericCertificate = new X509Certificate2(Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), \"genericcert.pfx\"), \"password\")\n};\n\n// Fired when a CONNECT request is received\nexplicitEndPoint.BeforeTunnelConnectRequest += OnBeforeTunnelConnectRequest;\n\n// An explicit endpoint is where the client knows about the existence of a proxy\n// So client sends request in a proxy friendly manner\nproxyServer.AddEndPoint(explicitEndPoint);\nproxyServer.Start();\n\n// Transparent endpoint is useful for reverse proxy (client is not aware of the existence of proxy)\n// A transparent endpoint usually requires a network router port forwarding HTTP(S) packets or DNS\n// to send data to this endPoint\nvar transparentEndPoint = new TransparentProxyEndPoint(IPAddress.Any, 8001, true)\n{\n    // Generic Certificate hostname to use\n    // when SNI is disabled by client\n    GenericCertificateName = \"google.com\"\n};\n\nproxyServer.AddEndPoint(transparentEndPoint);\n\n//proxyServer.UpStreamHttpProxy = new ExternalProxy() { HostName = \"localhost\", Port = 8888 };\n//proxyServer.UpStreamHttpsProxy = new ExternalProxy() { HostName = \"localhost\", Port = 8888 };\n\nforeach (var endPoint in proxyServer.ProxyEndPoints)\nConsole.WriteLine(\"Listening on '{0}' endpoint at Ip {1} and port: {2} \",\n    endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);\n\n// Only explicit proxies can be set as system proxy!\nproxyServer.SetAsSystemHttpProxy(explicitEndPoint);\nproxyServer.SetAsSystemHttpsProxy(explicitEndPoint);\n\n// wait here (You can use something else as a wait function, I am using this as a demo)\nConsole.Read();\n\n// Unsubscribe \u0026 Quit\nexplicitEndPoint.BeforeTunnelConnectRequest -= OnBeforeTunnelConnectRequest;\nproxyServer.BeforeRequest -= OnRequest;\nproxyServer.BeforeResponse -= OnResponse;\nproxyServer.ServerCertificateValidationCallback -= OnCertificateValidation;\nproxyServer.ClientCertificateSelectionCallback -= OnCertificateSelection;\n\nproxyServer.Stop();\n```\n\nSample request and response event handlers\n\n```csharp\nprivate async Task OnBeforeTunnelConnectRequest(object sender, TunnelConnectSessionEventArgs e)\n{\n    string hostname = e.HttpClient.Request.RequestUri.Host;\n\n    if (hostname.Contains(\"dropbox.com\"))\n    {\n         // Exclude Https addresses you don't want to proxy\n         // Useful for clients that use certificate pinning\n         // for example dropbox.com\n         e.DecryptSsl = false;\n    }\n}\n\npublic async Task OnRequest(object sender, SessionEventArgs e)\n{\n    Console.WriteLine(e.HttpClient.Request.Url);\n\n    // read request headers\n    var requestHeaders = e.HttpClient.Request.Headers;\n\n    var method = e.HttpClient.Request.Method.ToUpper();\n    if ((method == \"POST\" || method == \"PUT\" || method == \"PATCH\"))\n    {\n        // Get/Set request body bytes\n        byte[] bodyBytes = await e.GetRequestBody();\n        e.SetRequestBody(bodyBytes);\n\n        // Get/Set request body as string\n        string bodyString = await e.GetRequestBodyAsString();\n        e.SetRequestBodyString(bodyString);\n    \n        // store request \n        // so that you can find it from response handler \n        e.UserData = e.HttpClient.Request;\n    }\n\n    // To cancel a request with a custom HTML content\n    // Filter URL\n    if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(\"google.com\"))\n    {\n        e.Ok(\"\u003c!DOCTYPE html\u003e\" +\n            \"\u003chtml\u003e\u003cbody\u003e\u003ch1\u003e\" +\n            \"Website Blocked\" +\n            \"\u003c/h1\u003e\" +\n            \"\u003cp\u003eBlocked by titanium web proxy.\u003c/p\u003e\" +\n            \"\u003c/body\u003e\" +\n            \"\u003c/html\u003e\");\n    }\n\n    // Redirect example\n    if (e.HttpClient.Request.RequestUri.AbsoluteUri.Contains(\"wikipedia.org\"))\n    {\n        e.Redirect(\"https://www.paypal.com\");\n    }\n}\n\n// Modify response\npublic async Task OnResponse(object sender, SessionEventArgs e)\n{\n    // read response headers\n    var responseHeaders = e.HttpClient.Response.Headers;\n\n    //if (!e.ProxySession.Request.Host.Equals(\"medeczane.sgk.gov.tr\")) return;\n    if (e.HttpClient.Request.Method == \"GET\" || e.HttpClient.Request.Method == \"POST\")\n    {\n        if (e.HttpClient.Response.StatusCode == 200)\n        {\n            if (e.HttpClient.Response.ContentType != null \u0026\u0026 e.HttpClient.Response.ContentType.Trim().ToLower().Contains(\"text/html\"))\n            {\n                byte[] bodyBytes = await e.GetResponseBody();\n                e.SetResponseBody(bodyBytes);\n\n                string body = await e.GetResponseBodyAsString();\n                e.SetResponseBodyString(body);\n            }\n        }\n    }\n    \n    if (e.UserData != null)\n    {\n        // access request from UserData property where we stored it in RequestHandler\n        var request = (Request)e.UserData;\n    }\n}\n\n// Allows overriding default certificate validation logic\npublic Task OnCertificateValidation(object sender, CertificateValidationEventArgs e)\n{\n    // set IsValid to true/false based on Certificate Errors\n    if (e.SslPolicyErrors == System.Net.Security.SslPolicyErrors.None)\n        e.IsValid = true;\n\n    return Task.CompletedTask;\n}\n\n// Allows overriding default client certificate selection logic during mutual authentication\npublic Task OnCertificateSelection(object sender, CertificateSelectionEventArgs e)\n{\n    // set e.clientCertificate to override\n    return Task.CompletedTask;\n}\n```\n\n### Console example application screenshot\n\n![alt tag](https://raw.githubusercontent.com/svrooij/Titanium-Web-Proxy/develop/examples/Titanium.Web.Proxy.Examples.Basic/Capture.PNG)\n\n### GUI example application screenshot\n\n![alt tag](https://raw.githubusercontent.com/svrooij/Titanium-Web-Proxy/develop/examples/Titanium.Web.Proxy.Examples.Wpf/Capture.PNG)\n\n[badge_issues]: https://img.shields.io/github/issues/svrooij/titanium-web-proxy?style=for-the-badge\n[badle_license]: https://img.shields.io/github/license/svrooij/titanium-web-proxy?style=for-the-badge\n[badge_nuget]: https://img.shields.io/nuget/v/Unobtanium.Web.Proxy?style=for-the-badge\n[badge_sponsor]: https://img.shields.io/github/sponsors/svrooij?style=for-the-badge\u0026logo=github\n[badge_twp-repo]: https://img.shields.io/badge/Unobtanium--Web--Proxy-Reboot-blue?style=for-the-badge\n[badge_twp_build]: https://img.shields.io/github/check-runs/svrooij/titanium-web-proxy/develop?style=for-the-badge\n\n[link_build]: https://github.com/svrooij/titanium-web-proxy/actions/workflows/dotnetcore.yml\n[link_issues]: https://github.com/svrooij/titanium-web-proxy/issues\n[link_license]: https://github.com/svrooij/titanium-web-proxy?tab=MIT-1-ov-file\n[link_nuget]: https://www.nuget.org/packages/Unobtanium.Web.Proxy\n[link_twp-repo]: https://github.com/svrooij/titanium-web-proxy\n[link_sponsor]: https://github.com/sponsors/svrooij\n","funding_links":["https://github.com/sponsors/svrooij","https://www.paypal.com"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvrooij%2Funobtanium-web-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsvrooij%2Funobtanium-web-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsvrooij%2Funobtanium-web-proxy/lists"}