Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
MultiGetResource.cs
1using System;
3using System.IO;
4using System.Text;
5using System.Threading.Tasks;
6using Waher.Content;
11using Waher.Script;
12using Waher.Security;
13
15{
20 {
21 private readonly XmppClient client;
22 private readonly HttpServer webServer;
23 private readonly string userVariable;
24 private readonly string[] userPrivileges;
25
34 public MultiGetResource(string ResourceName, XmppClient Client, HttpServer WebServer, string UserVariable,
35 params string[] UserPrivileges)
36 : base(ResourceName)
37 {
38 this.client = Client;
39 this.webServer = WebServer;
40 this.userVariable = UserVariable;
41 this.userPrivileges = UserPrivileges;
42 }
43
47 public override bool HandlesSubPaths => false;
48
52 public override bool UserSessions => false;
53
57 public bool AllowsPOST => true;
58
65 public async Task POST(HttpRequest Request, HttpResponse Response)
66 {
67 string s = Request.RemoteEndPoint;
68 int i = s.IndexOf('/');
69 if (i > 0)
70 s = s[..i];
71
72 RosterItem Item = this.client[s];
73 bool Forbidden = false;
74
75 if (Item is null)
76 {
77 string HttpSessionID = GetSessionId(Request, Response);
78
79 if (string.IsNullOrEmpty(HttpSessionID))
80 Forbidden = true;
81 else
82 {
83 Variables Session = this.webServer.GetSession(HttpSessionID, false);
84 if (Session is null ||
85 !Session.TryGetVariable(this.userVariable, out Variable v) ||
86 !(v.ValueObject is IUser User))
87 {
88 Forbidden = true;
89 }
90 else
91 {
92 foreach (string Privilege in this.userPrivileges)
93 {
94 if (!User.HasPrivilege(Privilege))
95 {
96 Forbidden = true;
97 break;
98 }
99 }
100 }
101 }
102 }
103 else
104 {
105 if (Item.State != SubscriptionState.Both && Item.State != SubscriptionState.From)
106 Forbidden = true;
107 }
108
109 if (Forbidden)
110 {
111 await Response.SendResponse(new ForbiddenException(Request, "Access to resources not granted."));
112 return;
113 }
114
115 if (!Request.HasData)
116 {
117 await Response.SendResponse(new BadRequestException("No data."));
118 return;
119 }
120
121 ContentResponse Data = await Request.DecodeDataAsync();
122
123 if (Data.HasError)
124 {
125 await Response.SendResponse(Data.Error);
126 return;
127 }
128
129 if (!(Data.Decoded is string[][] Records) || !this.HasColumns(Records, 2))
130 {
131 await Response.SendResponse(new UnsupportedMediaTypeException("Data must be encoded as text/csv, each record two columns, first=resource, second=Accept header."));
132 return;
133 }
134
135 HttpFieldAccept Accept = Request.Header.Accept;
136 if (!(Accept is null) && !Accept.IsAcceptable("multipart/mixed"))
137 {
138 await Response.SendResponse(new NotAcceptableException());
139 return;
140 }
141
142 this.Process(Request, Response, Records);
143 }
144
145 private bool HasColumns(string[][] Records, int Nr)
146 {
147 foreach (string[] Record in Records)
148 {
149 if (Record.Length != Nr)
150 return false;
151 }
152
153 return true;
154 }
155
156 private async void Process(HttpRequest Request, HttpResponse Response, string[][] Records)
157 {
158 try
159 {
160 Uri OrgUri = new Uri(Request.Header.GetURL(false, false));
161 List<EmbeddedContent> Items = new List<EmbeddedContent>();
162 StringBuilder Header = new StringBuilder();
163 HttpRequestHeader H = Request.Header;
164
165 foreach (string[] Record in Records)
166 {
167 try
168 {
169 if (!Uri.TryCreate(OrgUri, Record[0], out Uri ItemUri))
170 {
171 await Response.SendResponse(new BadRequestException("Invalid URI: " + Record[0]));
172 return;
173 }
174
175 if (ItemUri.Scheme != OrgUri.Scheme || ItemUri.Authority != OrgUri.Authority)
176 {
177 await Response.SendResponse(new ForbiddenException(Request, "Cross-domain requests not permitted."));
178 return;
179 }
180
182 {
183 await Response.SendResponse(new ServiceUnavailableException("Service is shutting down. Please try again later.",
184 new KeyValuePair<string, string>("Retry-After", "300")));
185 }
186
187 string ResourcePath = ItemUri.LocalPath;
188 if (!this.webServer.TryGetResource(ref ResourcePath, out HttpResource Resource, out string SubPath) ||
189 !(Resource is IHttpGetMethod GetMethod))
190 {
191 await Response.SendResponse(new NotFoundException("Resource not found."));
192 return;
193 }
194
195 using MemoryStream ms = new MemoryStream();
196 StringBuilder sb = new StringBuilder();
197 HttpFieldReferer Referer = Request.Header.Referer;
198 HttpFieldHost Host = Request.Header.Host;
199
200 sb.Append("GET ");
201 sb.Append(ItemUri.PathAndQuery);
202 sb.AppendLine(" HTTP/1.1");
203
204 if (!(Host is null))
205 {
206 sb.Append("Host: ");
207 sb.AppendLine(Host.Value);
208 }
209
210 if (!(Referer is null))
211 {
212 sb.Append("Referer: ");
213 sb.AppendLine(Referer.Value);
214 }
215
216 sb.Append("Accept: ");
217 sb.AppendLine(Record[1]);
218
219 HttpRequest Request2 = new HttpRequest(this.webServer, new HttpRequestHeader(sb.ToString(),
220 this.webServer.VanityResources, ItemUri.Scheme), null, Request.RemoteEndPoint, Request.LocalEndPoint)
221 {
222 Session = Request.Session,
223 SubPath = SubPath,
224 Resource = Resource
225 };
226
228 HttpResponse Response2 = new HttpResponse(InternalTransfer, this.webServer, Request2);
229
230 this.webServer.RequestReceived(Request2, Request.RemoteEndPoint, Resource, SubPath);
231 await GetMethod.GET(Request2, Response2);
232
233 await InternalTransfer.WaitUntilSent(10000);
234
235 byte[] Bin = ms.ToArray();
236
237 Items.Add(new EmbeddedContent()
238 {
239 ContentType = Response2.ContentType,
240 Size = Bin.Length,
241 Raw = Encoding.ASCII.GetBytes(Convert.ToBase64String(Bin)),
242 TransferEncoding = "base64",
243 Description = Response2.StatusCode.ToString()
244 });
245 }
246 catch (HttpException ex)
247 {
248 byte[] Bin = Encoding.UTF8.GetBytes(ex.Message);
249 Items.Add(new EmbeddedContent()
250 {
251 ContentType = "text/plain; charset=utf-8",
252 Size = Bin.Length,
253 Raw = Encoding.ASCII.GetBytes(Convert.ToBase64String(Bin)),
254 TransferEncoding = "base64",
255 Description = ex.StatusCode.ToString()
256 });
257 }
258 catch (Exception ex)
259 {
260 byte[] Bin = Encoding.UTF8.GetBytes(ex.Message);
261 Items.Add(new EmbeddedContent()
262 {
263 ContentType = "text/plain; charset=utf-8",
264 Size = Bin.Length,
265 Raw = Encoding.ASCII.GetBytes(Convert.ToBase64String(Bin)),
266 TransferEncoding = "base64",
267 Description = "500"
268 });
269 }
270 }
271
272 await Response.Return(new MixedContent(Items.ToArray()));
273 }
274 catch (Exception ex)
275 {
276 await Response.SendResponse(ex);
277 }
278 }
279
280 }
281}
Contains information about a response to a content request.
bool HasError
If an error occurred.
object Decoded
Decoded object.
Exception Error
Error response.
Represents content embedded in other content.
Represents mixed content, encoded with multipart/mixed
Definition: MixedContent.cs:7
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
Accept HTTP Field header. (RFC 2616, §14.1)
bool IsAcceptable(string Alternative)
Checks if an alternative is acceptable to the client sending a request.
Host HTTP Field header. (RFC 2616, §14.23)
Definition: HttpFieldHost.cs:7
Referer HTTP Field header. (RFC 2616, §14.36)
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
Base class of all HTTP Exceptions.
string Value
HTTP Field Value
Definition: HttpField.cs:31
Contains information about all fields in an HTTP request header.
HttpFieldReferer Referer
Referer HTTP Field header. (RFC 2616, §14.36)
HttpFieldHost Host
Host HTTP Field header. (RFC 2616, §14.23)
HttpFieldAccept Accept
Accept HTTP Field header. (RFC 2616, §14.1)
string GetURL()
Gets an absolute URL for the request.
Represents an HTTP request.
Definition: HttpRequest.cs:22
HttpRequestHeader Header
Request header.
Definition: HttpRequest.cs:182
string RemoteEndPoint
Remote end-point.
Definition: HttpRequest.cs:243
bool HasData
If the request has data.
Definition: HttpRequest.cs:113
SessionVariables Session
Contains session states, if the resource requires sessions, or null otherwise.
Definition: HttpRequest.cs:212
string LocalEndPoint
Local end-point.
Definition: HttpRequest.cs:248
async Task< ContentResponse > DecodeDataAsync()
Decodes data sent in request.
Definition: HttpRequest.cs:139
Base class for all HTTP resources.
Definition: HttpResource.cs:23
static string GetSessionId(HttpRequest Request, HttpResponse Response)
Gets the session ID used for a request.
const string HttpSessionID
The Cookie Key for HTTP Session Identifiers: "HttpSessionID"
Definition: HttpResource.cs:27
string ResourceName
Name of resource.
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
string ContentType
The Content-Type entity-header field indicates the media type of the entity-body sent to the recipien...
int StatusCode
HTTP Status code.
Task Return(Exception ex)
Returns an error to the client.
Implements an HTTP server.
Definition: HttpServer.cs:41
The resource identified by the request is only capable of generating response entities which have con...
The server has not found anything matching the Request-URI. No indication is given of whether the con...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
Base class for all transfer encodings.
Transfer encoding for internal transfers of content
Task WaitUntilSent(int TimeoutMilliseconds)
Waits for all of the data to be returned.
The server is refusing to service the request because the entity of the request is in a format not su...
Module that controls the life cycle of communication.
static bool Stopping
If the system is stopping.
Allows a client to get multiple resources in one call
override bool HandlesSubPaths
If the resource handles sub-paths.
MultiGetResource(string ResourceName, XmppClient Client, HttpServer WebServer, string UserVariable, params string[] UserPrivileges)
Allows a client to get multiple resources in one call
override bool UserSessions
If the resource uses user sessions.
async Task POST(HttpRequest Request, HttpResponse Response)
Executes the POST method on the resource.
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
SubscriptionState State
roup Current subscription state.
Definition: RosterItem.cs:268
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
Contains information about a variable.
Definition: Variable.cs:10
Collection of variables.
Definition: Variables.cs:25
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Definition: Variables.cs:56
GET Interface for HTTP resources.
POST Interface for HTTP resources.
Basic interface for a user.
Definition: IUser.cs:7
SubscriptionState
State of a presence subscription.
Definition: RosterItem.cs:16
ContentType
DTLS Record content type.
Definition: Enumerations.cs:11