private void HostLocalhost(ProxyContext ctx) { if (TrimHost("userstream.twitter.com")) { this.HostStreaming(ctx); return; } if (TrimHost("api.twitter.com")) { this.HostAPI(ctx); return; } ctx.Response.StatusCode = HttpStatusCode.BadRequest; bool TrimHost(string host) { if (ctx.Request.RequestUri.AbsolutePath.StartsWith($"/{host}/")) { ctx.Request.RequestUri = new UriBuilder(ctx.Request.RequestUri) { Host = host, Path = ctx.Request.RequestUri.AbsolutePath.Substring(host.Length + 1), }.Uri; return(true); } return(false); } }
public virtual async Task SetContentAsync( ProxyContext context, HttpResponseMessage upstreamResponse, CancellationToken cancellationToken) { CheckValue(context, nameof(context)); CheckValue(upstreamResponse, nameof(upstreamResponse)); cancellationToken.ThrowIfCancellationRequested(); if (upstreamResponse.Content is null) { Logger.LogDebug("The inbound upstream response does not have a content body."); return; } var contentLength = upstreamResponse.Content.Headers?.ContentLength; if (contentLength is not null && contentLength <= 0) { Logger.LogDebug("The inbound upstream response has a content length that is less than or equal to zero."); return; } await SetContentHeadersAsync(context, upstreamResponse, cancellationToken); await SetContentBodyAsync(context, upstreamResponse, cancellationToken); }
/// <summary> /// The Via general header is added by proxies, both forward and reverse proxies, and can appear in /// the request headers and the response headers. It is used for tracking message forwards, avoiding /// request loops, and identifying the protocol capabilities of senders along the request/response chain. /// See <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via">here</a> for more information. /// </summary> protected virtual void AddViaHeader(ProxyContext context, HttpRequestMessage upstreamRequest) { var builder = new StringBuilder(); if (!context.ProxyUpstreamRequestHeadersSettings.DiscardInboundHeaders) { if (context.Request.Headers.TryGetValue(HeaderNames.Via, out var values) && values.Count > 0) { foreach (var value in values) { builder.Append(value).AppendComma().AppendSpace(); } } } if (context.Request.Protocol.StartsWithOrdinalIgnoreCase(HttpProtocolPrefix)) { var version = context.RequestHttpVersion; builder.Append(version.Major).AppendDot().Append(version.Minor); } else { builder.Append(context.Request.Protocol); } builder.AppendSpace().Append(context.ProxyName); upstreamRequest.Headers.TryAddWithoutValidation( HeaderNames.Via, builder.ToString()); }
private async Task <bool> ProxyAsync(HttpContext httpContext) { if (!routeResolver.TryResolve(httpContext, out var route)) { return(false); } logger.LogDebug( "Reverse proxy found a matching route for the inbound downstream HTTP '{0}' request.", httpContext.Request.Method); var context = new ProxyContext( evaluator, httpContext, route); var cancellationToken = httpContext.RequestAborted; var upstreamRequest = await CreateUpstreamRequestAsync(context, cancellationToken); var upstreamResponse = await SendUpstreamRequestAsync(context, upstreamRequest, cancellationToken); await SendDownstreamResponseAsync(context, upstreamResponse, cancellationToken); return(true); }
protected virtual void AddServerHeader(ProxyContext context, HttpResponseMessage upstreamResponse) { AddHeaderValues( context, HeaderNames.Server, Constants.ServerName); }
protected override object GetProperty(object target, string propName, ProxyContext proxyContext) { if (propName == null) { throw new ArgumentNullException("propName"); } if (proxyContext == null) { throw new ArgumentNullException("proxyContext"); } CJG site = target as CJG; if (site == null) { throw new ArgumentNullException("target"); } propName = base.GetMemberName(propName, proxyContext); switch (propName) { case "FirstName": base.CheckBlockedGetProperty("FirstName", proxyContext); return(site.FirstName); } return(base.GetProperty(target, propName, proxyContext)); }
private bool HostAPI(ProxyContext ctx) { switch (ctx.Request.RequestUri.AbsolutePath) { // api 호출 후 스트리밍에 destroy 날려주는 함수 // POST https://api.twitter.com/1.1/statuses/destroy/:id.json // POST https://api.twitter.com/1.1/statuses/unretweet/:id.json case string path when path.StartsWith("/1.1/statuses/destroy/", StringComparison.OrdinalIgnoreCase) || path.StartsWith("/1.1/statuses/unretweet/", StringComparison.OrdinalIgnoreCase): return(HandleDestroyOrUnretweet(ctx)); // api 호출 후 스트리밍에 리트윗 날려주는 함수 // 404 : id = 삭제된 트윗일 수 있음 // 200 : 성공시 스트리밍에 전송해서 한번 더 띄우도록 // POST https://api.twitter.com/1.1/statuses/retweet/:id.json case string path when path.StartsWith("/1.1/statuses/retweet/", StringComparison.OrdinalIgnoreCase): return(HandleRetweet(ctx)); // d @ID 로 DM 보내는 기능 추가된 함수. // 401 : in_reply_to_status_id = 삭제된 트윗일 수 있음 // POST https://api.twitter.com/1.1/statuses/update.json case string path when path.Equals("/1.1/statuses/update.json", StringComparison.OrdinalIgnoreCase): return(HandleUpdate(ctx)); default: return(HandleTunnel(ctx)); } }
public virtual Task SetHeadersAsync( ProxyContext context, HttpResponseMessage upstreamResponse, CancellationToken cancellationToken) { CheckValue(context, nameof(context)); CheckValue(upstreamResponse, nameof(upstreamResponse)); cancellationToken.ThrowIfCancellationRequested(); var settings = context.ProxyDownstreamResponseHeaderSettings; if (!settings.DiscardInboundHeaders) { AddUpstreamResponseHeadersToDownstream(context, upstreamResponse); } if (settings.AddVia) { AddViaHeader(context, upstreamResponse); } if (settings.AddServer) { AddServerHeader(context, upstreamResponse); } AddExtraHeaders(context); return(Task.CompletedTask); }
static void Main(string[] args) { if (args.Intersect(new[] { "--help", "-h" }).Count() > 0 || args.Length > 1) { Console.WriteLine("./tgsocks [CONFIG_PATH]"); } var configPath = DefaultConfigPath; if (args.Length == 1) { configPath = args[0]; } if (!File.Exists(configPath)) { Console.WriteLine($"{configPath} not found"); return; } var config = Newtonsoft.Json.JsonConvert.DeserializeObject <Config>(File.ReadAllText(configPath)); var proxyContext = new ProxyContext(); proxyContext.CheckProto = true; proxyContext.DataCentres = config.DataCentres.ToArray(); proxyContext.Secret = Enumerable. Range(0, config.Secret.Length / 2). Select( x => Convert.ToByte( config.Secret.Substring(x * 2, 2), 16 ) ). ToArray(); Log("Secret: " + string.Join("", proxyContext.Secret.Select(x => x.ToString("x2")))); var proxyManager = new ProxyManager( proxyContext, config.ConnectionsPerThread, config.SelectTimeout, config.ReceiveBufferSize ); foreach (var srv in config.Servers) { var ip = IPAddress.Parse(srv.Host); var port = srv.Port; proxyManager.AddServer(new IPEndPoint(ip, port), ip.AddressFamily, srv.Backlog); } proxyManager.Connections.OnConnectionRegistered += Connections_OnConnectionRegistered; proxyManager.Connections.OnConnectionRemoved += Connections_OnConnectionRemoved; Log("OK, Load config complete, starting"); Console.CancelKeyPress += (a, b) => { Log("Stopping..."); proxyManager.Stop(); Log("Stopped"); }; proxyManager.Start(); Log("Server started"); System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); }
private static ForwardedHeaderValue CreateLatestForwardHeaderValue(ProxyContext context) { return(new ForwardedHeaderValue( by: CreateValidForwardedIpAddress(context.HttpContext.Connection.LocalIpAddress), @for: CreateValidForwardedIpAddress(context.HttpContext.Connection.RemoteIpAddress), host: context.Request.Host.Value, proto: context.Request.Scheme)); }
private async Task <HttpRequestMessage> CreateUpstreamRequestAsync( ProxyContext context, CancellationToken cancellationToken) { return(await requestCreator .CreateRequestAsync(context, cancellationToken) .TraceOnFaulted(logger, "Failed to create an outbound upstream request.", cancellationToken)); }
protected virtual void AddProxyNameHeader(ProxyContext context, HttpRequestMessage upstreamRequest) { AddHeaderValues( context, upstreamRequest, Names.ProxyName, context.ProxyName); }
public TimeSpan EvaluateTimeout(ProxyContext context) { var result = context.Evaluate(TimeoutInMillisecondsExpression); return(long.TryParse(result, out var timeout) && timeout > 0 ? TimeSpan.FromMilliseconds(timeout) : Defaults.Route.Proxy.Upstream.Request.Sender.Timeout); }
public static void CreateNonVerifiableContext() { var context = new ProxyContext(AssemblyBuilderAccess.RunAndSave, false, false); Assert.False(context.Verify); Assert.False(context.GenerateDebugging); Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run); Assert.True((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save); }
/// <summary> /// Response 전송 하므로 사용에 주의 /// 오류 발생 시 false 를 반환함. return 해줘야 함. /// </summary> private static bool TryCallAPIThenSetContext <T>(ProxyContext ctx, Stream proxyReqBody, TwitterClient client, out HttpStatusCode responseStatusCode, out T response) where T : class { var res = TryCallAPIThenSetContext(ctx, proxyReqBody, client, typeof(T), out responseStatusCode, out var obj); response = obj as T; return(res); }
public string EvaluateProxyName(ProxyContext context) { var eval = context.Evaluate(ProxyNameExpression); return(string.IsNullOrWhiteSpace(eval) ? Defaults.Route.Proxy.ProxyName : eval); }
protected override IEnumerable <MethodInformation> GetMethods(ProxyContext proxyContext) { if (proxyContext == null) { throw new ArgumentNullException("proxyContext"); } MethodInformation iteratorVariable1 = new MethodInformation { Name = "ReturnInt", IsStatic = false, OperationType = OperationType.Default, ClientLibraryTargets = ClientLibraryTargets.All, OriginalName = "ReturnInt", WildcardPath = false, ReturnType = typeof(int), ReturnODataType = ODataType.Primitive, RESTfulExtensionMethod = true, ResourceUsageHints = ResourceUsageHints.None, RequiredRight = ResourceRight.Default }; yield return(iteratorVariable1); MethodInformation iteratorVariable2 = new MethodInformation { Name = "ReturnDate", IsStatic = false, OperationType = OperationType.Default, ClientLibraryTargets = ClientLibraryTargets.All, OriginalName = "ReturnDate", WildcardPath = false, ReturnType = typeof(DateTime), ReturnODataType = ODataType.Primitive, RESTfulExtensionMethod = true, ResourceUsageHints = ResourceUsageHints.None, RequiredRight = ResourceRight.Default }; yield return(iteratorVariable2); MethodInformation iteratorVariable3 = new MethodInformation { Name = ".ctor", IsStatic = false, OperationType = OperationType.Default, ClientLibraryTargets = ClientLibraryTargets.RESTful, OriginalName = ".ctor", WildcardPath = false, ReturnType = null, ReturnODataType = ODataType.Invalid, RESTfulExtensionMethod = false, ResourceUsageHints = ResourceUsageHints.None, RequiredRight = ResourceRight.None }; yield return(iteratorVariable3); }
protected virtual void AddUpstreamResponseHeadersToDownstream( ProxyContext context, HttpResponseMessage upstreamResponse) { var headers = upstreamResponse.Headers; if (headers is null) { return; } var options = context.ProxyDownstreamResponseHeaderSettings; var discardEmpty = options.DiscardEmpty; var discardUnderscore = options.DiscardUnderscore; var doNotTransferHeaders = options.DoNotTransferHeaders; ICollection <string>?nonStandardHopByHopHeaders = null; // lazy instantiate if and only if needed foreach (var header in headers) { var name = header.Key; if (!sanitizer.IsValid( name, header.Value, discardEmpty, discardUnderscore)) { continue; } if (doNotTransferHeaders.Contains(name)) { continue; } var values = header.Value.AsStringValues(); if (name.EqualsOrdinalIgnoreCase(HeaderNames.SetCookie)) { UpdateSetCookiesValues(context, values); } else { if (nonStandardHopByHopHeaders is null) { nonStandardHopByHopHeaders = GetNonStandardHopByHopHeaders(headers); } if (nonStandardHopByHopHeaders.Contains(name)) { continue; } } AddHeaderValues(context, name, values); } }
public virtual bool TryGetHeaderValues( ProxyContext context, string name, StringValues downstreamValues, out StringValues upstreamValues) { upstreamValues = downstreamValues; return(true); }
protected override object InvokeConstructor(ClientValueCollection xmlargs, ProxyContext proxyContext) { if (proxyContext == null) { throw new ArgumentNullException("proxyContext"); } base.CheckBlockedMethod(".ctor", proxyContext); return(CJG_ConProxy(xmlargs, proxyContext)); }
public static void CreateDefaultContext() { var context = new ProxyContext(); Assert.False(context.Verify); Assert.False(context.GenerateDebugging); Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run); Assert.False((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save); }
private async Task SendDownstreamResponseAsync( ProxyContext context, HttpResponseMessage upstreamResponse, CancellationToken cancellationToken) { await responseSender .SendResponseAsync(context, upstreamResponse, cancellationToken) .TraceOnFaulted(logger, "Failed to create and send the downstream response message.", cancellationToken); }
public static void CreateSpecificContext() { var context = new ProxyContext( AssemblyBuilderAccess.RunAndSave, true, true); Assert.True(context.Verify); Assert.True(context.GenerateDebugging); Assert.True((context.Access & AssemblyBuilderAccess.Run) == AssemblyBuilderAccess.Run); Assert.True((context.Access & AssemblyBuilderAccess.Save) == AssemblyBuilderAccess.Save); }
/// <inheritdoc/> public Task <Uri> CreateAsync(ProxyContext context, CancellationToken cancellationToken) { var toExpression = context.ProxySettings.To; var to = evaluator.Evaluate(context, toExpression); string scheme; HostString host; PathString toPath; QueryString toQueryString; FragmentString fragment; try { UriHelper.FromAbsolute( to, out scheme, out host, out toPath, out toQueryString, out fragment); } catch (FormatException ufe) { var message = $"Using '{context.ProxySettings.To}' expression to rewrite request URL '{context.Request.Path}'. However, the rewritten URL is not a valid URL format."; logger.LogError(ufe, message); throw new UriFormatException(message, ufe); } if (!Uri.CheckSchemeName(scheme)) { throw new UriFormatException($"The HTTP scheme '{scheme}' specified by '{toExpression}' expression is invalid."); } if (!host.HasValue || Uri.CheckHostName(GetHostValue(host.Value)) == UriHostNameType.Unknown) { throw new UriFormatException($"The URL host '{host}' specified by '{toExpression}' expression is invalid."); } var path = ConcatPathWithSuffix(toPath, context.Route.PathSuffix); var queryString = toQueryString + context.Request.QueryString; var url = UriHelper.BuildAbsolute( scheme, host, PathString.Empty, path, queryString, fragment); if (Uri.TryCreate(url, UriKind.Absolute, out var uri)) { return(Task.FromResult(uri)); } throw new UriFormatException($"The URL '{url}' specified by '{toExpression}' expression is an invalid absolute HTTP URL."); }
private static void HandleTunnel(ProxyContext ctx) { TryGetTwitterClient(ctx, null, out var twitClient); if (!TryCallAPIThenSetContext(ctx, null, twitClient, null, out _, out _)) { ctx.Response.Headers.Clear(); ctx.Response.StatusCode = HttpStatusCode.InternalServerError; } }
private void SetStatusCode(ProxyContext context, HttpResponseMessage upstreamResponse) { if (context.Response.HasStarted) { logger.LogError("It is not possible to transfer the HTTP status code from the inbound upstream response to the outbound downstream response. This should never happen!"); return; } context.Response.StatusCode = (int)upstreamResponse.StatusCode; }
protected override object GetProperty(object target, string propName, ProxyContext proxyContext) { propName = GetMemberName(propName, proxyContext); switch (propName) { case "About": CheckBlockedGetProperty("About", proxyContext); return(((CustomService)target).About); } return(base.GetProperty(target, propName, proxyContext)); }
public static T CreateProxy <T>(this T @this, ProxyContext context, params IInvocationHandler[] handlers) where T : class { @this.CheckCreatePreconditions(handlers); var targetType = @this.GetType(); ProxyBuilder.Build(targetType, context); var arguments = new object[] { @this, handlers }; return(Activator.CreateInstance(BuiltProxies.Mappings[targetType], arguments) as T); }
private async Task SetHeadersAsync( ProxyContext context, HttpResponseMessage upstreamResponse, CancellationToken cancellationToken) { logger.LogDebug("Appending the HTTP headers to the outbound downstream response"); await headerSetter .SetHeadersAsync(context, upstreamResponse, cancellationToken) .TraceOnFaulted(logger, "Failed to set the headers on the outbound downstream response", cancellationToken); logger.LogDebug("Appended the HTTP headers to the outbound downstream response"); }
private async Task SetHeadersAsync( ProxyContext context, HttpRequestMessage upstreamRequest, CancellationToken cancellationToken) { logger.LogDebug("Appending the HTTP headers to the outbound upstream request"); await headerSetter .SetHeadersAsync(context, upstreamRequest, cancellationToken) .TraceOnFaulted(logger, "Failed to set the content body of the outbound upstream request", cancellationToken); logger.LogDebug("Appended the HTTP headers to the outbound upstream request"); }
private async Task SetContentAsync( ProxyContext context, HttpResponseMessage upstreamResponse, CancellationToken cancellationToken) { logger.LogDebug("Transferring the content of the inbound upstream response to the outbound downstream response"); await contentSetter .SetContentAsync(context, upstreamResponse, cancellationToken) .TraceOnFaulted(logger, "Failed to set the content body of the outbound downstream response", cancellationToken); logger.LogDebug("Transferred the content of the inbound upstream response to the outbound downstream response"); }