2using System.Collections.Generic;
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(
"/"))
201 Url = Url.Substring(1);
203 if (!Url.StartsWith(
"httpx://", StringComparison.OrdinalIgnoreCase))
206 int i = Url.IndexOf(
'/', 8);
210 string BareJID = Url.Substring(8, i - 8);
211 string LocalUrl = Url.Substring(i);
215 if (Method ==
"GET" && !(this.httpxCache is
null))
217 if (!((CachedResource = await this.httpxCache.
TryGetCachedResource(BareJID, LocalUrl)) is
null))
226 DateTimeOffset? Limit;
236 CachedResource.
LastModified.UtcDateTime, Response, Request);
242 RosterItem Item = this.defaultXmppClient.GetRosterItem(BareJID);
250 throw new ConflictException(
"No approved presence subscription with " + BareJID +
".");
258 if (!(this.serverlessMessaging is
null))
271 await this.SendRequest(this.httpxClient, e.
From, Method, BareJID, LocalUrl, Request, Response);
297 throw new ArgumentException(
"URI must use URI Scheme HTTPX.", nameof(Uri));
299 string BareJID = Uri.UserInfo +
"@" + Uri.Authority;
300 string LocalUrl = Uri.PathAndQuery + Uri.Fragment;
302 RosterItem Item = this.defaultXmppClient.GetRosterItem(BareJID);
305 if (BareJID.IndexOf(
'@') < 0)
321 throw new ConflictException(
"No approved presence subscription with " + BareJID +
".");
325 TaskCompletionSource<HttpxClient> Result =
new TaskCompletionSource<HttpxClient>();
329 if (!(this.serverlessMessaging is
null))
333 if (e2.Client is null)
334 Result.TrySetResult(this.httpxClient);
337 if (e2.Client.SupportsFeature(HttpxClient.Namespace) &&
338 e2.Client.TryGetTag(
"HttpxClient", out object Obj) &&
339 Obj is HttpxClient Client)
341 Result.TrySetResult(Client);
344 Result.TrySetResult(this.httpxClient);
347 return Task.CompletedTask;
351 Result.TrySetResult(this.httpxClient);
368 private class SendP2pRec
371 public string method;
372 public string fullJID;
373 public string localUrl;
380 SendP2pRec Rec = (SendP2pRec)e.
State;
386 await this.SendRequest(this.httpxClient, Rec.fullJID, Rec.method,
XmppClient.
GetBareJID(Rec.fullJID),
387 Rec.localUrl, Rec.request, Rec.response);
393 Obj is HttpxClient Client)
396 Rec.localUrl, Rec.request, Rec.response);
400 await this.SendRequest(this.httpxClient, Rec.fullJID, Rec.method,
XmppClient.
GetBareJID(Rec.fullJID),
401 Rec.localUrl, Rec.request, Rec.response);
407 await Rec.response.SendResponse(ex);
411 private Task SendRequest(HttpxClient HttpxClient,
string To,
string Method,
string BareJID,
string LocalUrl,
414 LinkedList<HttpField> Headers =
new LinkedList<HttpField>();
418 switch (Header.
Key.ToLower())
421 Headers.AddLast(
new HttpField(
"Host", BareJID));
430 Headers.AddLast(Header);
435 ReadoutState State =
new ReadoutState(Response, BareJID, LocalUrl)
437 Cacheable = (Method ==
"GET" && !(this.httpxCache is
null))
441 int i = s.IndexOf(
'.');
444 s = s.Substring(i + 1);
445 i = s.IndexOfAny(
new char[] {
'?',
'#' });
447 s = s.Substring(0, i);
451 LinkedListNode<HttpField> Loop = Headers.First;
452 LinkedListNode<HttpField> Next;
454 while (!(Loop is
null))
458 switch (Loop.Value.Key.ToLower())
461 case "if-modified-since":
462 case "if-none-match":
464 case "if-unmodified-since":
465 Headers.Remove(Loop);
475 this.RequestResponse,
this.ResponseData, State);
478 private async Task RequestResponse(
object Sender, HttpxResponseEventArgs e)
480 ReadoutState State2 = (ReadoutState)e.State;
482 State2.Response.StatusCode = e.StatusCode;
483 State2.Response.StatusMessage = e.StatusMessage;
485 if (!(e.HttpResponse is
null))
487 foreach (KeyValuePair<string, string> Field
in e.HttpResponse.GetHeaders())
489 switch (Field.Key.ToLower())
497 State2.ContentType = Field.Value;
498 State2.Response.SetHeader(Field.Key, Field.Value);
502 State2.ETag = Field.Value;
503 State2.Response.SetHeader(Field.Key, Field.Value);
506 case "last-modified":
509 State2.LastModified = TP;
510 State2.Response.SetHeader(Field.Key, Field.Value);
516 State2.Response.SetHeader(Field.Key, Field.Value);
519 case "cache-control":
520 State2.CacheControl = Field.Value;
521 State2.Response.SetHeader(Field.Key, Field.Value);
525 State2.Pragma = Field.Value;
526 State2.Response.SetHeader(Field.Key, Field.Value);
530 State2.Response.SetHeader(Field.Key, Field.Value);
537 await State2.Response.SendResponse();
540 if (e.StatusCode == 200 && State2.Cacheable && State2.CanCache &&
541 this.httpxCache.CanCache(State2.BareJid, State2.LocalResource, State2.ContentType))
546 if (!(e.Data is
null))
547 await this.BinaryDataReceived(State2,
true, e.Data);
551 private Task ResponseData(
object Sender, HttpxResponseDataEventArgs e)
553 ReadoutState State2 = (ReadoutState)e.State;
555 return this.BinaryDataReceived(State2, e.Last, e.Data);
558 private async Task BinaryDataReceived(ReadoutState State2,
bool Last,
byte[] Data)
562 await State2.Response.Write(Data);
570 State2.TempOutput?.Write(Data, 0, Data.Length);
574 await State2.Response.SendResponse();
575 this.AddToCacheAsync(State2);
579 private async
void AddToCacheAsync(ReadoutState State)
583 if (!(State.TempOutput is
null))
585 State.TempOutput.Position = 0;
587 await this.httpxCache.
AddToCache(State.BareJid, State.LocalResource, State.ContentType, State.ETag,
588 State.LastModified.Value, State.Expires, State.TempOutput);
601 catch (Exception ex2)
608 private class ReadoutState : IDisposable
610 public bool Cacheable =
false;
612 public string ETag =
null;
613 public string BareJid =
null;
614 public string LocalResource =
null;
616 public string CacheControl =
null;
617 public string Pragma =
null;
618 public DateTimeOffset? Expires =
null;
619 public DateTimeOffset? LastModified =
null;
622 public ReadoutState(
HttpResponse Response,
string BareJid,
string LocalResource)
624 this.Response = Response;
625 this.BareJid = BareJid;
626 this.LocalResource = LocalResource;
633 if (this.ETag is
null || !this.LastModified.HasValue)
636 if (!(this.CacheControl is
null))
638 if ((this.CacheControl.Contains(
"no-cache") ||
this.CacheControl.Contains(
"no-store")))
641 if (!this.Expires.HasValue)
643 string s = this.CacheControl;
644 int i = s.IndexOf(
"max-age");
648 while (i < c && ((ch = s[i]) <=
' ' || ch ==
'=' || ch == 160))
653 while (j < c && (ch = s[j]) >=
'0' && ch <=
'9')
656 if (j > i &&
int.TryParse(s.Substring(i, j - i), out j))
657 this.Expires = DateTimeOffset.UtcNow.AddSeconds(j);
661 if (!(this.Pragma is
null) && this.Pragma.Contains(
"no-cache"))
668 public void Dispose()
670 if (!(this.TempOutput is
null))
673 this.TempOutput =
null;
681 public bool AllowsGET
694 return this.Request(
"GET", Request, Response);
706 return this.Request(
"GET", Request, Response);
717 return this.Request(
"OPTIONS", Request, Response);
723 public bool AllowsPOST
736 return this.Request(
"POST", Request, Response);
748 return this.Request(
"POST", Request, Response);
754 public bool AllowsPUT
767 return this.Request(
"PUT", Request, Response);
779 return this.Request(
"PUT", Request, Response);
785 public bool AllowsPATCH
798 return this.Request(
"PATCH", Request, Response);
810 return this.Request(
"PATCH", Request, Response);
816 public bool AllowsTRACE
829 return this.Request(
"TRACE", Request, Response);
835 public bool AllowsDELETE
848 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.
string Key
HTTP Field Name
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, 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...
ContentType
DTLS Record content type.