/// <summary> /// Gets a (possibly big) resource, using a Uniform Resource Identifier (or Locator). /// </summary> /// <param name="Uri">URI</param> /// <param name="TimeoutMs">Timeout, in milliseconds. (Default=60000)</param> /// <param name="Headers">Optional headers. Interpreted in accordance with the corresponding URI scheme.</param> /// <exception cref="InvalidOperationException">No <see cref="HttpxProxy"/> set in the HTTPX <see cref="Types"/> module parameter.</exception> /// <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> /// <exception cref="TimeoutException">If the request times out.</exception> /// <returns>Content-Type, together with a Temporary file, if resource has been downloaded, or null if resource is data-less.</returns> public async Task <KeyValuePair <string, TemporaryFile> > GetTempFileAsync(Uri Uri, int TimeoutMs, params KeyValuePair <string, string>[] Headers) { if (proxy is null) { if (!Types.TryGetModuleParameter("HTTPX", out object Obj) || !(Obj is HttpxProxy Proxy)) { throw new InvalidOperationException("A HTTPX Proxy object has not been registered."); } proxy = Proxy; } GetClientResponse Rec = await proxy.GetClientAsync(Uri); List <HttpField> Headers2 = new List <HttpField>(); foreach (KeyValuePair <string, string> Header in Headers) { switch (Header.Key.ToLower()) { case "host": Headers2.Add(new HttpField("Host", Rec.BareJid)); break; case "cookie": case "set-cookie": // Do not forward cookies. break; default: Headers2.Add(new HttpField(Header.Key, Header.Value)); break; } } State State = null; Timer Timer = null; try { State = new State(); Timer = new Timer((P) => { State.Done.TrySetResult(false); }, null, TimeoutMs, Timeout.Infinite); Rec.HttpxClient.Request(Rec.FullJid, "GET", Rec.LocalUrl, (sender, e) => { if (e.Ok) { State.HttpResponse = e.HttpResponse; if (e.StatusCode >= 200 && e.StatusCode < 300) { if (e.HasData) { State.File = new TemporaryFile(); if (!(e.Data is null)) { State.File.Write(e.Data, 0, e.Data.Length); State.Done.TrySetResult(true); } } else { State.Done.TrySetResult(true); } }
/// <summary> /// Posts to a resource, using a Uniform Resource Identifier (or Locator). /// </summary> /// <param name="Uri">URI</param> /// <param name="EncodedData">Encoded data to be posted.</param> /// <param name="ContentType">Content-Type of encoded data in <paramref name="EncodedData"/>.</param> /// <param name="TimeoutMs">Timeout, in milliseconds. (Default=60000)</param> /// <param name="Headers">Optional headers. Interpreted in accordance with the corresponding URI scheme.</param> /// <returns>Encoded response.</returns> /// <exception cref="InvalidOperationException">No <see cref="HttpxProxy"/> set in the HTTPX <see cref="Types"/> module parameter.</exception> /// <exception cref="ArgumentException">If the <paramref name="Uri"/> parameter is invalid.</exception> /// <exception cref="ArgumentException">If the object response be decoded.</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> /// <exception cref="TimeoutException">If the request times out.</exception> /// <exception cref="OutOfMemoryException">If resource too large to decode.</exception> /// <exception cref="IOException">If unable to read from temporary file.</exception> public async Task <KeyValuePair <byte[], string> > PostAsync(Uri Uri, byte[] EncodedData, string ContentType, int TimeoutMs, params KeyValuePair <string, string>[] Headers) { if (proxy is null) { if (!Types.TryGetModuleParameter("HTTPX", out object Obj) || !(Obj is HttpxProxy Proxy)) { throw new InvalidOperationException("A HTTPX Proxy object has not been registered."); } proxy = Proxy; } GetClientResponse Rec = await proxy.GetClientAsync(Uri); List <HttpField> Headers2 = new List <HttpField>(); bool HasContentType = false; foreach (KeyValuePair <string, string> Header in Headers) { switch (Header.Key.ToLower()) { case "host": Headers2.Add(new HttpField("Host", Rec.BareJid)); break; case "cookie": case "set-cookie": // Do not forward cookies. break; case "content-type": Headers2.Add(new HttpField(Header.Key, Header.Value)); HasContentType = true; break; default: Headers2.Add(new HttpField(Header.Key, Header.Value)); break; } } if (!HasContentType) { Headers2.Add(new HttpField("Content-Type", ContentType)); } MemoryStream Data = new MemoryStream(EncodedData); State State = null; Timer Timer = null; try { State = new State(); Timer = new Timer((P) => { State.Done.TrySetResult(false); }, null, TimeoutMs, Timeout.Infinite); Rec.HttpxClient.Request(Rec.FullJid, "POST", Rec.LocalUrl, 1.1, Headers2, Data, async(sender, e) => { if (e.Ok) { State.HttpResponse = e.HttpResponse; State.StatusCode = e.StatusCode; State.StatusMessage = e.StatusMessage; if (e.HasData) { State.Data = new MemoryStream(); if (!(e.Data is null)) { await State.Data.WriteAsync(e.Data, 0, e.Data.Length); State.Done.TrySetResult(true); } } else { State.Done.TrySetResult(true); } } else { State.Done.TrySetException(new IOException(string.IsNullOrEmpty(e.ErrorText) ? "Unable to get resource." : e.ErrorText)); } }, async(sender, e) => { await State.Data.WriteAsync(e.Data, 0, e.Data.Length); if (e.Last) { State.Done.TrySetResult(true); } }, State); if (!await State.Done.Task) { throw new TimeoutException("Request timed out."); } Timer.Dispose(); Timer = null; if (State.StatusCode >= 200 && State.StatusCode < 300) { return(new KeyValuePair <byte[], string>(State.Data?.ToArray(), State.HttpResponse?.ContentType)); } else { ContentType = string.Empty; EncodedData = State.Data?.ToArray(); throw HttpxGetter.GetExceptionObject(State.StatusCode, State.StatusMessage, State.HttpResponse, EncodedData, ContentType); } } finally { State.Data?.Dispose(); State.Data = null; State.HttpResponse?.Dispose(); State.HttpResponse = null; Timer?.Dispose(); Timer = null; Data.Dispose(); } }
/// <summary> /// Gets a (possibly big) resource, using a Uniform Resource Identifier (or Locator). /// </summary> /// <param name="Uri">URI</param> /// <param name="TimeoutMs">Timeout, in milliseconds. (Default=60000)</param> /// <param name="Headers">Optional headers. Interpreted in accordance with the corresponding URI scheme.</param> /// <exception cref="InvalidOperationException">No <see cref="HttpxProxy"/> set in the HTTPX <see cref="Types"/> module parameter.</exception> /// <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> /// <exception cref="TimeoutException">If the request times out.</exception> /// <returns>Content-Type, together with a Temporary file, if resource has been downloaded, or null if resource is data-less.</returns> public async Task <KeyValuePair <string, TemporaryStream> > GetTempStreamAsync(Uri Uri, int TimeoutMs, params KeyValuePair <string, string>[] Headers) { if (proxy is null) { if (!Types.TryGetModuleParameter("HTTPX", out object Obj) || !(Obj is HttpxProxy Proxy)) { throw new InvalidOperationException("A HTTPX Proxy object has not been registered."); } proxy = Proxy; } GetClientResponse Rec = await proxy.GetClientAsync(Uri); List <HttpField> Headers2 = new List <HttpField>(); bool HasHost = false; foreach (KeyValuePair <string, string> Header in Headers) { switch (Header.Key.ToLower()) { case "host": Headers2.Add(new HttpField("Host", Rec.BareJid)); HasHost = true; break; case "cookie": case "set-cookie": // Do not forward cookies. break; default: Headers2.Add(new HttpField(Header.Key, Header.Value)); break; } } if (!HasHost) { Headers2.Add(new HttpField("Host", Uri.Authority)); } State State = null; Timer Timer = null; try { State = new State(); Timer = new Timer((P) => { State.Done.TrySetResult(false); }, null, TimeoutMs, Timeout.Infinite); Rec.HttpxClient.Request(Rec.FullJid, "GET", Rec.LocalUrl, async(sender, e) => { if (e.Ok) { State.HttpResponse = e.HttpResponse; State.StatusCode = e.StatusCode; State.StatusMessage = e.StatusMessage; if (e.HasData) { State.File = new TemporaryStream(); if (!(e.Data is null)) { await State.File.WriteAsync(e.Data, 0, e.Data.Length); State.Done.TrySetResult(true); } } else { State.Done.TrySetResult(true); } } else { State.Done.TrySetException(e.StanzaError ?? new Exception("Unable to get resource.")); } }, async(sender, e) => { await(State.File?.WriteAsync(e.Data, 0, e.Data.Length) ?? Task.CompletedTask); if (e.Last) { State.Done?.TrySetResult(true); } }, State, Headers2.ToArray()); if (!await State.Done.Task) { throw new TimeoutException("Request timed out."); } Timer.Dispose(); Timer = null; if (State.StatusCode >= 200 && State.StatusCode < 300) { TemporaryStream Result = State.File; State.File = null; return(new KeyValuePair <string, TemporaryStream>(State.HttpResponse?.ContentType, Result)); } else { string ContentType = string.Empty; byte[] Data; if (State.File is null) { Data = null; } else { int Len = (int)State.File.Length; ContentType = State.HttpResponse.ContentType; State.File.Position = 0; Data = new byte[Len]; await State.File.ReadAsync(Data, 0, Len); } throw GetExceptionObject(State.StatusCode, State.StatusMessage, State.HttpResponse, Data, ContentType); } } finally { State.File?.Dispose(); State.File = null; State.HttpResponse?.Dispose(); State.HttpResponse = null; Timer?.Dispose(); Timer = null; } }