Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
HttpxPutter.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Security.Cryptography.X509Certificates;
5using System.Threading;
6using System.Threading.Tasks;
7using Waher.Content;
11
13{
20 public class HttpxPutter : PutterBase
21 {
28 public HttpxPutter()
29 {
30 }
31
35 public override string[] UriSchemes => new string[] { HttpxGetter.HttpxUriScheme };
36
43 public override bool CanPut(Uri Uri, out Grade Grade)
44 {
45 switch (Uri.Scheme)
46 {
48 Grade = Grade.Ok;
49 return true;
50
51 default:
52 Grade = Grade.NotAtAll;
53 return false;
54 }
55 }
56
76 public override async Task<KeyValuePair<byte[], string>> PutAsync(Uri Uri, byte[] EncodedData, string ContentType,
77 X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs,
78 params KeyValuePair<string, string>[] Headers)
79 {
81 string BareJid;
82 string FullJid;
83 string LocalUrl;
84
85 if (Types.TryGetModuleParameter("HTTPX", out object Obj) && Obj is HttpxProxy Proxy)
86 {
87 if (Proxy.DefaultXmppClient.Disposed || Proxy.ServerlessMessaging.Disposed)
88 throw new InvalidOperationException("Service is being shut down.");
89
90 GetClientResponse Rec = await Proxy.GetClientAsync(Uri);
91
92 BareJid = Rec.BareJid;
93 FullJid = Rec.FullJid;
95 LocalUrl = Rec.LocalUrl;
96 }
97 else if (Types.TryGetModuleParameter("XMPP", out Obj) && Obj is XmppClient XmppClient)
98 {
100 throw new InvalidOperationException("Service is being shut down.");
101
102 if (!XmppClient.TryGetExtension(out HttpxClient HttpxClient2))
103 throw new InvalidOperationException("No HTTPX Extesion has been registered on the XMPP Client.");
104
105 HttpxClient = HttpxClient2;
106
107 if (string.IsNullOrEmpty(Uri.UserInfo))
108 FullJid = BareJid = Uri.Authority;
109 else
110 {
111 BareJid = Uri.UserInfo + "@" + Uri.Authority;
112
113 RosterItem Item = XmppClient.GetRosterItem(BareJid);
114
115 if (Item is null)
116 throw new ConflictException("No approved presence subscription with " + BareJid + ".");
117 else if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
118 throw new ServiceUnavailableException(BareJid + " is not online.");
119 else
120 FullJid = Item.LastPresenceFullJid;
121 }
122
123 LocalUrl = Uri.PathAndQuery + Uri.Fragment;
124 }
125 else
126 throw new InvalidOperationException("An HTTPX Proxy or XMPP Client Module Parameter has not been registered.");
127
128 List<HttpField> Headers2 = new List<HttpField>();
129 bool HasContentType = false;
130 bool HasHost = false;
131
132 foreach (KeyValuePair<string, string> Header in Headers)
133 {
134 switch (Header.Key.ToLower())
135 {
136 case "host":
137 Headers2.Add(new HttpField("Host", BareJid));
138 HasHost = true;
139 break;
140
141 case "cookie":
142 case "set-cookie":
143 // Do not forward cookies.
144 break;
145
146 case "content-type":
147 Headers2.Add(new HttpField(Header.Key, Header.Value));
148 HasContentType = true;
149 break;
150
151 default:
152 Headers2.Add(new HttpField(Header.Key, Header.Value));
153 break;
154 }
155 }
156
157 if (!HasContentType)
158 Headers2.Add(new HttpField("Content-Type", ContentType));
159
160 if (!HasHost)
161 Headers2.Add(new HttpField("Host", Uri.Authority));
162
163 MemoryStream Data = new MemoryStream(EncodedData);
164 State State = null;
165 Timer Timer = null;
166
167 try
168 {
169 State = new State();
170 Timer = new Timer((P) =>
171 {
172 State.Done.TrySetResult(false);
173 }, null, TimeoutMs, Timeout.Infinite);
174
175 // TODO: Transport public part of Client certificate, if provided.
176
177 await HttpxClient.Request(FullJid, "PUT", LocalUrl, 1.1, Headers2, Data, async (Sender, e) =>
178 {
179 if (e.Ok)
180 {
181 State.HttpResponse = e.HttpResponse;
182 State.StatusCode = e.StatusCode;
183 State.StatusMessage = e.StatusMessage;
184
185 if (e.HasData)
186 {
187 if (State.Data is null)
188 State.Data = new MemoryStream();
189
190 if (!(e.Data is null))
191 {
192 await State.Data.WriteAsync(e.Data, 0, e.Data.Length);
193 State.Done.TrySetResult(true);
194 }
195 }
196 else
197 State.Done.TrySetResult(true);
198 }
199 else
200 State.Done.TrySetException(e.StanzaError ?? new Exception("Unable to get resource."));
201
202 }, async (Sender, e) =>
203 {
204 if (State.Data is null)
205 State.Data = new MemoryStream();
206
207 await State.Data.WriteAsync(e.Data, 0, e.Data.Length);
208 if (e.Last)
209 State.Done.TrySetResult(true);
210
211 }, State);
212
213 if (!await State.Done.Task)
214 throw new TimeoutException("Request timed out.");
215
216 Timer.Dispose();
217 Timer = null;
218
219 if (State.StatusCode >= 200 && State.StatusCode < 300)
220 return new KeyValuePair<byte[], string>(State.Data?.ToArray(), State.HttpResponse?.ContentType);
221 else
222 {
223 ContentType = string.Empty;
224 EncodedData = State.Data?.ToArray();
225
226 throw HttpxGetter.GetExceptionObject(State.StatusCode, State.StatusMessage,
227 State.HttpResponse, EncodedData, ContentType);
228 }
229 }
230 finally
231 {
232 State.Data?.Dispose();
233 State.Data = null;
234
235 if (!(State.HttpResponse is null))
236 {
237 await State.HttpResponse.DisposeAsync();
238 State.HttpResponse = null;
239 }
240
241 Timer?.Dispose();
242 Timer = null;
243
244 Data.Dispose();
245 }
246 }
247
248 private class State
249 {
250 public HttpResponse HttpResponse = null;
251 public MemoryStream Data = null;
252 public TaskCompletionSource<bool> Done = new TaskCompletionSource<bool>();
253 public string StatusMessage = string.Empty;
254 public int StatusCode = 0;
255 }
256
257 }
258}
Abstract base class for putters.
Definition: PutterBase.cs:13
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:21
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:252
Content Getter, retrieving content using the HTTPX URI Scheme.
Definition: HttpxGetter.cs:21
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
Definition: HttpxProxy.cs:19
Content Putter, puting content using the HTTPX URI Scheme.
Definition: HttpxPutter.cs:21
HttpxPutter()
Content Putter, puting content using the HTTPX URI Scheme.
Definition: HttpxPutter.cs:28
override async Task< KeyValuePair< byte[], string > > PutAsync(Uri Uri, byte[] EncodedData, string ContentType, X509Certificate Certificate, RemoteCertificateEventHandler RemoteCertificateValidator, int TimeoutMs, params KeyValuePair< string, string >[] Headers)
Puts to a resource, using a Uniform Resource Identifier (or Locator).
Definition: HttpxPutter.cs:76
override bool CanPut(Uri Uri, out Grade Grade)
If the putter is able to put to a resource, given its URI.
Definition: HttpxPutter.cs:43
override string[] UriSchemes
Supported URI schemes.
Definition: HttpxPutter.cs:35
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:59
bool Disposed
If the client has been disposed.
Definition: XmppClient.cs:1192
bool TryGetExtension(Type Type, out IXmppExtension Extension)
Tries to get a registered extension of a specific type from the client.
Definition: XmppClient.cs:7318
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Definition: XmppClient.cs:4522
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:583
delegate void RemoteCertificateEventHandler(object Sender, RemoteCertificateEventArgs e)
Delegate for remote certificate event handlers.
Grade
Grade enumeration
Definition: Grade.cs:7