3using System.Threading.Tasks;
27 private bool disposed =
false;
67 this.httpxClient =
new HttpxClient(this.defaultXmppClient, MaxChunkSize)
79 this.httpxClient =
null;
93 get => this.postResource;
96 this.postResource = value;
98 if (!(this.httpxClient is
null))
99 this.httpxClient.PostResource = value;
108 get => this.serverlessMessaging;
111 if (!(this.serverlessMessaging is
null) && this.serverlessMessaging != value)
112 throw new Exception(
"Property already set.");
114 this.serverlessMessaging = value;
123 get => this.httpxCache;
126 if (!(this.httpxCache is
null) && this.httpxCache != value)
127 throw new Exception(
"Property already set.");
129 this.httpxCache = value;
148 get => this.ibbClient;
151 this.ibbClient = value;
153 if (!(this.httpxClient is
null))
154 this.httpxClient.IbbClient = value;
163 get => this.socks5Proxy;
166 this.socks5Proxy = value;
168 if (!(this.httpxClient is
null))
169 this.httpxClient.Socks5Proxy = value;
200 if (Url.StartsWith(
"/"))
203 if (!Url.StartsWith(
"httpx://", StringComparison.OrdinalIgnoreCase))
206 int i = Url.IndexOf(
'/', 8);
210 string BareJID = Url[8..i];
211 string LocalUrl = Url[i..];
215 if (Method ==
"GET" && !(this.httpxCache is
null))
217 if (!((CachedResource = await this.httpxCache.
TryGetCachedResource(BareJID, LocalUrl)) is
null))
229 DateTimeOffset? Limit;
241 CachedResource.
LastModified.UtcDateTime,
false, Response, Request);
247 RosterItem Item = this.defaultXmppClient.GetRosterItem(BareJID);
255 throw new ConflictException(
"No approved presence subscription with " + BareJID +
".");
263 if (!(this.serverlessMessaging is
null))
276 await this.SendRequest(this.httpxClient, e.
From, Method, BareJID, LocalUrl, Request, Response);
302 throw new ArgumentException(
"URI must use URI Scheme HTTPX.", nameof(Uri));
304 string BareJID = Uri.UserInfo +
"@" + Uri.Authority;
305 string LocalUrl = Uri.PathAndQuery + Uri.Fragment;
307 RosterItem Item = this.defaultXmppClient.GetRosterItem(BareJID);
310 if (BareJID.IndexOf(
'@') < 0)
326 throw new ConflictException(
"No approved presence subscription with " + BareJID +
".");
330 TaskCompletionSource<HttpxClient> Result =
new TaskCompletionSource<HttpxClient>();
334 if (!(this.serverlessMessaging is
null))
338 if (e2.Client is null)
339 Result.TrySetResult(this.httpxClient);
342 if (e2.Client.SupportsFeature(HttpxClient.Namespace) &&
343 e2.Client.TryGetTag(
"HttpxClient", out object Obj) &&
344 Obj is HttpxClient Client)
346 Result.TrySetResult(Client);
349 Result.TrySetResult(this.httpxClient);
352 return Task.CompletedTask;
356 Result.TrySetResult(this.httpxClient);
373 private class SendP2pRec
376 public string method;
377 public string fullJID;
378 public string localUrl;
385 SendP2pRec Rec = (SendP2pRec)e.
State;
391 await this.SendRequest(this.httpxClient, Rec.fullJID, Rec.method,
XmppClient.
GetBareJID(Rec.fullJID),
392 Rec.localUrl, Rec.request, Rec.response);
398 Obj is HttpxClient Client)
401 Rec.localUrl, Rec.request, Rec.response);
405 await this.SendRequest(this.httpxClient, Rec.fullJID, Rec.method,
XmppClient.
GetBareJID(Rec.fullJID),
406 Rec.localUrl, Rec.request, Rec.response);
412 await Rec.response.SendResponse(ex);
416 private Task SendRequest(HttpxClient HttpxClient,
string To,
string Method,
string BareJID,
string LocalUrl,
419 LinkedList<HttpField> Headers =
new LinkedList<HttpField>();
423 switch (
Header.Key.ToLower())
426 Headers.AddLast(
new HttpField(
"Host", BareJID));
435 Headers.AddLast(Header);
440 ReadoutState State =
new ReadoutState(Response, BareJID, LocalUrl)
442 Cacheable = (Method ==
"GET" && !(this.httpxCache is
null))
446 int i = s.IndexOf(
'.');
450 i = s.IndexOfAny(
new char[] {
'?',
'#' });
456 LinkedListNode<HttpField> Loop = Headers.First;
457 LinkedListNode<HttpField> Next;
459 while (!(Loop is
null))
463 switch (Loop.Value.Key.ToLower())
466 case "if-modified-since":
467 case "if-none-match":
469 case "if-unmodified-since":
470 Headers.Remove(Loop);
480 this.RequestResponse,
this.ResponseData, State);
483 private async Task RequestResponse(
object Sender, HttpxResponseEventArgs e)
485 ReadoutState State2 = (ReadoutState)e.State;
487 State2.Response.StatusCode = e.StatusCode;
488 State2.Response.StatusMessage = e.StatusMessage;
490 if (!(e.HttpResponse is
null))
492 foreach (KeyValuePair<string, string> Field
in e.HttpResponse.GetHeaders())
494 switch (Field.Key.ToLower())
502 State2.ContentType = Field.Value;
503 State2.Response.SetHeader(Field.Key, Field.Value);
507 State2.ETag = Field.Value;
508 State2.Response.SetHeader(Field.Key, Field.Value);
511 case "last-modified":
514 State2.LastModified = TP;
515 State2.Response.SetHeader(Field.Key, Field.Value);
521 State2.Response.SetHeader(Field.Key, Field.Value);
524 case "cache-control":
525 State2.CacheControl = Field.Value;
526 State2.Response.SetHeader(Field.Key, Field.Value);
530 State2.Pragma = Field.Value;
531 State2.Response.SetHeader(Field.Key, Field.Value);
535 State2.Response.SetHeader(Field.Key, Field.Value);
542 await State2.Response.SendResponse();
545 if (e.StatusCode == 200 && State2.Cacheable && State2.CanCache &&
546 this.httpxCache.CanCache(State2.BareJid, State2.LocalResource, State2.ContentType))
551 if (!(e.Data is
null))
552 await this.BinaryDataReceived(State2,
true, e.ConstantBuffer, e.Data);
556 private Task ResponseData(
object Sender, HttpxResponseDataEventArgs e)
558 ReadoutState State2 = (ReadoutState)e.State;
560 return this.BinaryDataReceived(State2, e.Last, e.ConstantBuffer, e.Data);
563 private async Task BinaryDataReceived(ReadoutState State2,
bool Last,
bool ConstantBuffer,
byte[] Data)
567 await State2.Response.Write(ConstantBuffer, Data);
575 State2.TempOutput?.Write(Data, 0, Data.Length);
579 await State2.Response.SendResponse();
580 this.AddToCacheAsync(State2);
584 private async
void AddToCacheAsync(ReadoutState State)
588 if (!(State.TempOutput is
null))
590 State.TempOutput.Position = 0;
592 await this.httpxCache.
AddToCache(State.BareJid, State.LocalResource, State.ContentType, State.ETag,
593 State.LastModified.Value, State.Expires, State.TempOutput);
606 catch (Exception ex2)
613 private class ReadoutState : IDisposable
615 public bool Cacheable =
false;
617 public string ETag =
null;
618 public string BareJid =
null;
619 public string LocalResource =
null;
621 public string CacheControl =
null;
622 public string Pragma =
null;
623 public DateTimeOffset? Expires =
null;
624 public DateTimeOffset? LastModified =
null;
627 public ReadoutState(
HttpResponse Response,
string BareJid,
string LocalResource)
629 this.Response = Response;
630 this.BareJid = BareJid;
631 this.LocalResource = LocalResource;
638 if (this.ETag is
null || !this.LastModified.HasValue)
641 if (!(this.CacheControl is
null))
643 if ((this.CacheControl.Contains(
"no-cache") ||
this.CacheControl.Contains(
"no-store")))
646 if (!this.Expires.HasValue)
648 string s = this.CacheControl;
649 int i = s.IndexOf(
"max-age");
653 while (i < c && ((ch = s[i]) <=
' ' || ch ==
'=' || ch == 160))
658 while (j < c && (ch = s[j]) >=
'0' && ch <=
'9')
661 if (j > i &&
int.TryParse(s[i..j], out j))
662 this.Expires = DateTimeOffset.UtcNow.AddSeconds(j);
666 if (!(this.Pragma is
null) && this.Pragma.Contains(
"no-cache"))
673 public void Dispose()
675 if (!(this.TempOutput is
null))
678 this.TempOutput =
null;
686 public bool AllowsGET
699 return this.Request(
"GET", Request, Response);
711 return this.Request(
"GET", Request, Response);
722 return this.Request(
"OPTIONS", Request, Response);
728 public bool AllowsPOST
741 return this.Request(
"POST", Request, Response);
753 return this.Request(
"POST", Request, Response);
759 public bool AllowsPUT
772 return this.Request(
"PUT", Request, Response);
784 return this.Request(
"PUT", Request, Response);
790 public bool AllowsPATCH
803 return this.Request(
"PATCH", Request, Response);
815 return this.Request(
"PATCH", Request, Response);
821 public bool AllowsTRACE
834 return this.Request(
"TRACE", Request, Response);
840 public bool AllowsDELETE
853 return this.Request(
"DELETE", Request, Response);
Helps with parsing of commong data types.
static bool TryParseRfc822(string s, out DateTimeOffset Value)
Parses a date and time value encoded according to RFC 822, §5.
Static class managing encoding and decoding of internet content.
static string GetContentType(string FileExtension)
Gets the content type of an item, given its file extension. It uses the TryGetContentType to see if a...
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
Represents a range in a ranged HTTP request or response.
The request could not be completed due to a conflict with the current state of the resource....
Represents a content range in a ranged HTTP request or response.
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
Base class for all HTTP fields.
Publishes a folder with all its files and subfolders through HTTP GET, with optional support for PUT,...
static Task SendResponse(string FullPath, string ContentType, string ETag, DateTime LastModified, bool LastModifiedUpdated, HttpResponse Response)
Sends a file-based response back to the client.
static bool LessOrEqual(DateTime LastModified, DateTimeOffset Limit)
Computes LastModified <=Limit . The normal <= operator behaved strangely, and did not get the equalit...
Represents an HTTP request.
Stream DataStream
Data stream, if data is available, or null if data is not available.
HttpRequestHeader Header
Request header.
bool HasData
If the request has data.
string SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
string ResourceName
Name of resource.
Represets a response of an HTTP client request.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
If the client has performed a conditional GET request and access is allowed, but the document has not...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
Event arguments for presence events.
string From
From where the presence was received.
Response to the HttpxProxy.GetClientAsync(Uri) method call.
override void Dispose()
Disposes of the extension.
Content Getter, retrieving content using the HTTPX URI Scheme.
const string HttpxUriScheme
httpx
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
HttpxProxy(string ResourceName, XmppClient DefaultXmppClient, int MaxChunkSize, XmppServerlessMessaging ServerlessMessaging, IHttpxCache HttpxCache)
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
override Task OPTIONS(HttpRequest Request, HttpResponse Response)
Executes the OPTIONS method on the resource.
Task TRACE(HttpRequest Request, HttpResponse Response)
Executes the TRACE method on the resource.
XmppServerlessMessaging ServerlessMessaging
Serverless messaging manager.
Task POST(HttpRequest Request, HttpResponse Response)
Executes the POST method on the resource.
Task PUT(HttpRequest Request, HttpResponse Response, ContentByteRangeInterval Interval)
Executes the ranged PUT method on the resource.
InBandBytestreams.IbbClient IbbClient
In-band bytestream client, if supported.
Task PUT(HttpRequest Request, HttpResponse Response)
Executes the PUT method on the resource.
Task GET(HttpRequest Request, HttpResponse Response)
Executes the GET method on the resource.
Task DELETE(HttpRequest Request, HttpResponse Response)
Executes the DELETE method on the resource.
Task PATCH(HttpRequest Request, HttpResponse Response)
Executes the PATCH method on the resource.
HttpxClient DefaultHttpxClient
Default HTTPX client.
bool Disposed
If the proxy has been disposed.
P2P.SOCKS5.Socks5Proxy Socks5Proxy
SOCKS5 proxy, if supported.
IHttpxCache HttpxCache
Reference to the HTTPX Cache manager.
Task PATCH(HttpRequest Request, HttpResponse Response, ContentByteRangeInterval Interval)
Executes the ranged PATCH method on the resource.
HttpxProxy(string ResourceName, XmppClient DefaultXmppClient, int MaxChunkSize)
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
async Task< GetClientResponse > GetClientAsync(Uri Uri)
Gets a corresponding HttpxClient appropriate for a given request.
override bool UserSessions
If the resource uses user sessions.
HttpxProxy(string ResourceName, XmppClient DefaultXmppClient, int MaxChunkSize, XmppServerlessMessaging ServerlessMessaging)
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
void Dispose()
IDisposable.Dispose
IPostResource PostResource
Post resource for responses.
override bool HandlesSubPaths
If the resource handles sub-paths.
Task GET(HttpRequest Request, HttpResponse Response, ByteRangeInterval FirstInterval)
Executes the ranged GET method on the resource.
Task POST(HttpRequest Request, HttpResponse Response, ContentByteRangeInterval Interval)
Executes the ranged POST method on the resource.
XmppClient DefaultXmppClient
Default XMPP client.
Class sending and receiving binary streams over XMPP using XEP-0047: In-band Bytestreams: https://xmp...
Peer connection event arguments.
object State
State object passed to the original request.
XmppClient Client
XMPP client, if aquired, or null otherwise.
Class managing a SOCKS5 proxy associated with the current XMPP server.
Class managing peer-to-peer serveless XMPP communication.
Task GetPeerConnection(string FullJID, EventHandlerAsync< PeerConnectionEventArgs > Callback, object State)
Gets a peer XMPP connection.
Maintains information about an item in the roster.
PresenceEventArgs[] Resources
Active resources utilized by contact.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
static string GetBareJID(string JID)
Gets the Bare JID from a JID, which may be a Full JID.
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
bool SupportsFeature(string Feature)
Checks if a feature is supported by the client.
bool TryGetTag(string TagName, out object Tag)
Tries to get a tag from the client. Tags can be used to attached application specific objects to the ...
Manages a temporary stream. Contents is kept in-memory, if below a memory threshold,...
override void Dispose(bool disposing)
Releases the unmanaged resources used by the System.IO.Stream and optionally releases the managed res...
DELETE Interface for HTTP resources.
GET Interface for HTTP resources.
Ranged GET Interface for HTTP resources.
PATCH Interface for HTTP resources.
Ranged PATCH Interface for HTTP resources.
POST Interface for HTTP resources.
Ranged POST Interface for HTTP resources.
PUT Interface for HTTP resources.
Ranged PUT Interface for HTTP resources.
TRACE Interface for HTTP resources.
Interface for HTTPX caches. HTTPX caches can improve performance by storing resources locally.
bool CanCache(string BareJid, string LocalResource, string ContentType)
Checks if content from a remote resource can be cached.
Task< IHttpxCachedResource > TryGetCachedResource(string BareJid, string LocalResource)
Tries to get a reference to the resource from the local cache.
Task AddToCache(string BareJid, string LocalResource, string ContentType, string ETag, DateTimeOffset LastModified, DateTimeOffset? Expires, Stream Content)
Adds content to the cache.
Interface for HTTPX Cache resource items.
string ETag
ETag of resource.
string ContentType
Content Type of resource.
string FileName
Name of file of local resource.
DateTimeOffset LastModified
When resource was last modified on remote peer.
Interface for HTTP(S) Post-back resources. These can be used to allow HTTPX servers to HTTP POST back...
class Header(ISimulationNode Parent, Model Model)
Represents an identity property.
ContentType
DTLS Record content type.