/// <summary> /// Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX. /// </summary> /// <param name="ResourceName">Resource name of proxy resource.</param> /// <param name="DefaultXmppClient">Default XMPP client.</param> /// <param name="MaxChunkSize">Max Chunk Size to use.</param> /// <param name="ServerlessMessaging">Serverless messaging manager.</param> /// <param name="HttpxCache">HTTPX cache object.</param> public HttpxProxy(string ResourceName, XmppClient DefaultXmppClient, int MaxChunkSize, XmppServerlessMessaging ServerlessMessaging, IHttpxCache HttpxCache) : base(ResourceName) { this.defaultXmppClient = DefaultXmppClient; this.httpxClient = new HttpxClient(this.defaultXmppClient, MaxChunkSize); this.serverlessMessaging = ServerlessMessaging; this.httpxCache = HttpxCache; }
/// <summary> /// <see cref="IDisposable.Dispose"/> /// </summary> public void Dispose() { if (this.httpxClient != null) { this.httpxClient.Dispose(); this.httpxClient = null; } }
internal ClientChunkRecord(HttpxClient Client, HttpxResponseEventArgs e, HttpResponse Response, HttpxResponseDataEventHandler DataCallback, object State, string StreamId, string Jid, bool E2e) : base() { this.client = Client; this.e = e; this.response = Response; this.dataCallback = DataCallback; this.state = State; this.streamId = StreamId; this.jid = Jid; this.e2e = E2e; }
internal ClientChunkRecord(HttpxClient Client, HttpxResponseEventArgs e, HttpResponse Response, HttpxResponseDataEventHandler DataCallback, object State, string StreamId, string From, string To, bool E2e, string EndpointReference, IE2eSymmetricCipher SymmetricCipher) : base() { this.client = Client; this.e = e; this.response = Response; this.dataCallback = DataCallback; this.state = State; this.streamId = StreamId; this.from = From; this.to = To; this.e2e = E2e; this.endpointReference = EndpointReference; this.symmetricCipher = SymmetricCipher; }
private void SendRequest(HttpxClient HttpxClient, string To, string Method, string BareJID, string LocalUrl, HttpRequest Request, HttpResponse Response) { LinkedList <HttpField> Headers = new LinkedList <HttpField>(); foreach (HttpField Header in Request.Header) { switch (Header.Key.ToLower()) { case "host": Headers.AddLast(new HttpField("Host", BareJID)); break; case "cookie": case "set-cookie": // Do not forward cookies. break; default: Headers.AddLast(Header); break; } } ReadoutState State = new ReadoutState(Response, BareJID, LocalUrl) { Cacheable = (Method == "GET" && this.httpxCache != null) }; string s = LocalUrl; int i = s.IndexOf('.'); if (i > 0) { s = s.Substring(i + 1); i = s.IndexOfAny(new char[] { '?', '#' }); if (i > 0) { s = s.Substring(0, i); } if (this.httpxCache.CanCache(BareJID, LocalUrl, InternetContent.GetContentType(s))) { LinkedListNode <HttpField> Loop = Headers.First; LinkedListNode <HttpField> Next; while (Loop != null) { Next = Loop.Next; switch (Loop.Value.Key.ToLower()) { case "if-match": case "if-modified-since": case "if-none-match": case "if-range": case "if-unmodified-since": Headers.Remove(Loop); break; } Loop = Next; } } } HttpxClient.Request(To, Method, LocalUrl, Request.Header.HttpVersion, Headers, Request.HasData ? Request.DataStream : null, this.RequestResponse, this.ResponseData, State); }
/// <summary> /// Gets a corresponding <see cref="HttpxClient"/> appropriate for a given request. /// </summary> /// <param name="Uri">URI</param> /// <returns>Contains details of the <paramref name="Uri"/> and the corresponding <see cref="HttpxClient"/> to use /// for requesting the resource from the entity.</returns> /// <exception cref="ArgumentException">If the <paramref name="Uri"/> parameter is invalid.</exception> /// <exception cref="ConflictException">If an approved presence subscription with the remote entity does not exist.</exception> /// <exception cref="ServiceUnavailableException">If the remote entity is not online.</exception> public async Task <GetClientResponse> GetClientAsync(Uri Uri) { if (string.Compare(Uri.Scheme, "httpx", true) != 0) { throw new ArgumentException("URI must use URI Scheme HTTPX.", nameof(Uri)); } string BareJID = Uri.UserInfo + "@" + Uri.Authority; string LocalUrl = Uri.PathAndQuery + Uri.Fragment; RosterItem Item = this.defaultXmppClient.GetRosterItem(BareJID); if (Item is null) { if (!XmppClient.BareJidRegEx.IsMatch(BareJID)) { throw new BadRequestException("Invalid Bare JID."); } // TODO: Request presence subscription, if user authenticated and request valid. throw new ConflictException("No approved presence subscription with " + BareJID + "."); } else { TaskCompletionSource <HttpxClient> Result = new TaskCompletionSource <HttpxClient>(); foreach (PresenceEventArgs e in Item.Resources) { if (this.serverlessMessaging != null) { this.serverlessMessaging.GetPeerConnection(e.From, (sender, e2) => { if (e2.Client is null) { Result.TrySetResult(this.httpxClient); } else { if (e2.Client.SupportsFeature(HttpxClient.Namespace) && e2.Client.TryGetTag("HttpxClient", out object Obj) && Obj is HttpxClient Client) { Result.TrySetResult(Client); } else { Result.TrySetResult(this.httpxClient); } } }, null); } else { Result.TrySetResult(this.httpxClient); } HttpxClient Client2 = await Result.Task; return(new GetClientResponse() { FullJid = e.From, BareJid = BareJID, LocalUrl = LocalUrl, HttpxClient = Client2 }); } throw new ServiceUnavailableException(BareJID + " not online."); } }
/// <summary> /// <see cref="IDisposable.Dispose"/> /// </summary> public void Dispose() { this.httpxClient?.Dispose(); this.httpxClient = null; }