Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
HttpxPoster.cs
1using System;
3using System.IO;
4using System.Security.Cryptography.X509Certificates;
5using System.Threading;
6using System.Threading.Tasks;
7using Waher.Content;
9using Waher.Events;
12
14{
21 public class HttpxPoster : PosterBase
22 {
29 public HttpxPoster()
30 {
31 }
32
36 public override string[] UriSchemes => new string[] { HttpxGetter.HttpxUriScheme };
37
44 public override bool CanPost(Uri Uri, out Grade Grade)
45 {
46 switch (Uri.Scheme)
47 {
49 Grade = Grade.Ok;
50 return true;
51
52 default:
53 Grade = Grade.NotAtAll;
54 return false;
55 }
56 }
57
78 public override async Task<ContentBinaryResponse> PostAsync(Uri Uri, byte[] EncodedData, string ContentType,
79 X509Certificate Certificate, EventHandler<RemoteCertificateEventArgs> RemoteCertificateValidator, int TimeoutMs,
80 params KeyValuePair<string, string>[] Headers)
81 {
83 string BareJid;
84 string FullJid;
85 string LocalUrl;
86
87 if (Types.TryGetModuleParameter("HTTPX", out HttpxProxy Proxy))
88 {
89 if (Proxy.DefaultXmppClient.Disposed || Proxy.ServerlessMessaging.Disposed)
90 return new ContentBinaryResponse(new InvalidOperationException("Service is being shut down."));
91
92 GetClientResponse Rec = await Proxy.GetClientAsync(Uri);
93
94 BareJid = Rec.BareJid;
95 FullJid = Rec.FullJid;
97 LocalUrl = Rec.LocalUrl;
98 }
100 {
102 return new ContentBinaryResponse(new InvalidOperationException("Service is being shut down."));
103
104 if (!XmppClient.TryGetExtension(out HttpxClient HttpxClient2))
105 return new ContentBinaryResponse(new InvalidOperationException("No HTTPX Extesion has been registered on the XMPP Client."));
106
107 HttpxClient = HttpxClient2;
108
109 if (string.IsNullOrEmpty(Uri.UserInfo))
110 FullJid = BareJid = Uri.Authority;
111 else
112 {
113 BareJid = Uri.UserInfo + "@" + Uri.Authority;
114
115 RosterItem Item = XmppClient.GetRosterItem(BareJid);
116
117 if (Item is null)
118 return new ContentBinaryResponse(new ConflictException("No approved presence subscription with " + BareJid + "."));
119 else if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
120 return new ContentBinaryResponse(new ServiceUnavailableException(BareJid + " is not online."));
121 else
122 FullJid = Item.LastPresenceFullJid;
123 }
124
125 LocalUrl = Uri.PathAndQuery + Uri.Fragment;
126 }
127 else
128 return new ContentBinaryResponse(new InvalidOperationException("An HTTPX Proxy or XMPP Client Module Parameter has not been registered."));
129
130 List<HttpField> Headers2 = new List<HttpField>();
131 bool HasContentType = false;
132 bool HasHost = false;
133
134 foreach (KeyValuePair<string, string> Header in Headers)
135 {
136 switch (Header.Key.ToLower())
137 {
138 case "host":
139 Headers2.Add(new HttpField("Host", BareJid));
140 HasHost = true;
141 break;
142
143 case "cookie":
144 case "set-cookie":
145 // Do not forward cookies.
146 break;
147
148 case "content-type":
149 Headers2.Add(new HttpField(Header.Key, Header.Value));
150 HasContentType = true;
151 break;
152
153 default:
154 Headers2.Add(new HttpField(Header.Key, Header.Value));
155 break;
156 }
157 }
158
159 if (!HasContentType && !string.IsNullOrEmpty(ContentType))
160 Headers2.Add(new HttpField("Content-Type", ContentType));
161
162 if (!HasHost)
163 Headers2.Add(new HttpField("Host", Uri.Authority));
164
165 MemoryStream Data = new MemoryStream(EncodedData);
166 State State = null;
167 Timer Timer = null;
168
169 try
170 {
171 State = new State();
172 Timer = new Timer((P) =>
173 {
174 State.Done.TrySetResult(false);
175 }, null, TimeoutMs, Timeout.Infinite);
176
177 // TODO: Transport public part of Client certificate, if provided.
178
179 await HttpxClient.Request(FullJid, "POST", LocalUrl, 1.1, Headers2, Data, async (Sender, e) =>
180 {
181 if (e.Ok)
182 {
183 State.HttpResponse = e.HttpResponse;
184 State.StatusCode = e.StatusCode;
185 State.StatusMessage = e.StatusMessage;
186
187 if (e.HasData)
188 {
189 State.Data ??= new MemoryStream();
190
191 if (!(e.Data is null))
192 {
193 await State.Data.WriteAsync(e.Data, 0, e.Data.Length);
194 State.Done.TrySetResult(true);
195 }
196 }
197 else
198 State.Done.TrySetResult(true);
199 }
200 else
201 {
202 State.Done.TrySetException((Exception)e.StanzaError ??
203 new GenericException("Unable to post resource.", null, Uri.OriginalString));
204 }
205
206 }, async (Sender, e) =>
207 {
208 State.Data ??= new MemoryStream();
209
210 await State.Data.WriteAsync(e.Data, 0, e.Data.Length);
211 if (e.Last)
212 State.Done.TrySetResult(true);
213
214 }, State);
215
216 if (!await State.Done.Task)
217 return new ContentBinaryResponse(new GenericException(new TimeoutException("Request timed out."), null, Uri.OriginalString));
218
219 Timer.Dispose();
220 Timer = null;
221
222 if (State.StatusCode >= 200 && State.StatusCode < 300)
223 return new ContentBinaryResponse(State.HttpResponse?.ContentType, State.Data?.ToArray());
224 else
225 {
226 ContentType = string.Empty;
227 EncodedData = State.Data?.ToArray();
228
229 return new ContentBinaryResponse(HttpxGetter.GetExceptionObject(State.StatusCode, State.StatusMessage,
230 State.HttpResponse, EncodedData, ContentType));
231 }
232 }
233 finally
234 {
235 State.Data?.Dispose();
236 State.Data = null;
237
238 if (!(State.HttpResponse is null))
239 {
240 await State.HttpResponse.DisposeAsync();
241 State.HttpResponse = null;
242 }
243
244 Timer?.Dispose();
245 Timer = null;
246
247 Data.Dispose();
248 }
249 }
250
251 private class State
252 {
253 public HttpResponse HttpResponse = null;
254 public MemoryStream Data = null;
255 public TaskCompletionSource<bool> Done = new TaskCompletionSource<bool>();
256 public string StatusMessage = string.Empty;
257 public int StatusCode = 0;
258 }
259
260 }
261}
Contains information about a binary response to a content request.
Abstract base class for posters.
Definition: PosterBase.cs:13
Generic exception, with meta-data for logging.
The request could not be completed due to a conflict with the current state of the resource....
Base class for all HTTP fields.
Definition: HttpField.cs:7
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
Response to the HttpxProxy.GetClientAsync(Uri) method call.
string BareJid
Bare JID of entity hosting the resource.
HttpxClient HttpxClient
Corresponding HttpxClient object to use for the request..
string FullJid
Full JID of entity hosting the resource.
Task Request(string To, string Method, string LocalResource, EventHandlerAsync< HttpxResponseEventArgs > Callback, EventHandlerAsync< HttpxResponseDataEventArgs > DataCallback, object State, params HttpField[] Headers)
Performs an HTTP request.
Definition: HttpxClient.cs:255
Content Getter, retrieving content using the HTTPX URI Scheme.
Definition: HttpxGetter.cs:23
Content Poster, posting content using the HTTPX URI Scheme.
Definition: HttpxPoster.cs:22
HttpxPoster()
Content Poster, posting content using the HTTPX URI Scheme.
Definition: HttpxPoster.cs:29
override bool CanPost(Uri Uri, out Grade Grade)
If the poster is able to post to a resource, given its URI.
Definition: HttpxPoster.cs:44
override async Task< ContentBinaryResponse > PostAsync(Uri Uri, byte[] EncodedData, string ContentType, X509Certificate Certificate, EventHandler< RemoteCertificateEventArgs > RemoteCertificateValidator, int TimeoutMs, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Definition: HttpxPoster.cs:78
override string[] UriSchemes
Supported URI schemes.
Definition: HttpxPoster.cs:36
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
Definition: HttpxProxy.cs:19
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
bool HasLastPresence
If the roster item has received presence from an online resource having the given bare JID.
Definition: RosterItem.cs:425
string LastPresenceFullJid
Full JID of last resource sending online presence.
Definition: RosterItem.cs:343
PresenceEventArgs LastPresence
Last presence received from a resource having this bare JID.
Definition: RosterItem.cs:356
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
bool Disposed
If the client has been disposed.
Definition: XmppClient.cs:1173
bool TryGetExtension(Type Type, out IXmppExtension Extension)
Tries to get a registered extension of a specific type from the client.
Definition: XmppClient.cs:7391
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Definition: XmppClient.cs:4571
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:15
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:607
Grade
Grade enumeration
Definition: Grade.cs:7