4using System.Threading.Tasks;
21 private const int MaxSecondsIdle = 90;
45 Result.Removed += Result_Removed;
54 e.Value.Removed =
true;
55 await e.
Value.DisposeAsync();
96 if (
string.IsNullOrEmpty(Xml))
99 Response.
SetHeader(
"Cache-Control",
"max-age=0, no-cache, no-store");
101 this.Process(Xml, Request, Response);
103 return Task.CompletedTask;
122 if (l >
int.MaxValue)
129 byte[] Data =
new byte[Len];
130 Request.DataStream.Position = 0;
133 string Xml = Encoding.UTF8.GetString(Data);
134 this.Process(Xml, Request, Response);
141 await this.ProcessFragment(Xml, Request, Response);
158 bool HasNamespace =
false;
161 for (i = 0; i < c; i++)
187 await this.BoshError(Response,
"Invalid Request");
196 if (ch ==
'>' || ch ==
'/')
198 if (Depth == 1 && !HasNamespace)
200 Name =
" xmlns='" + XmppClientConnection.C2SNamespace +
"'";
201 Xml = Xml.Insert(i, Name);
219 HasNamespace =
false;
231 if (ch ==
'>' || ch ==
'/')
233 if (Depth == 1 && !HasNamespace)
235 Name =
" xmlns='" + XmppClientConnection.C2SNamespace +
"'";
236 Xml = Xml.Insert(i, Name);
258 Name = Xml[Start..i];
284 await this.BoshError(Response,
"Invalid Request");
294 await this.BoshError(Response,
"Invalid Request");
323 await this.BoshError(Response,
"Invalid Request");
333 await this.BoshError(Response,
"Invalid Request");
343 await this.BoshError(Response,
"Invalid Request");
353 await this.BoshError(Response,
"Invalid Request");
363 await this.BoshError(Response,
"Invalid Request");
373 await this.BoshError(Response,
"Invalid Request");
414 Body = Doc.DocumentElement;
415 if (Body is
null || Body.LocalName !=
"body" || Body.NamespaceURI !=
HttpBindNamespace)
419 string Language =
"en";
424 string NewKey =
null;
426 double Version =
double.MaxValue;
430 int WaitSeconds = 30;
432 bool Terminate =
false;
434 foreach (XmlAttribute Attribute
in Body.Attributes)
436 switch (Attribute.Name)
443 From = Attribute.
Value;
447 if (!
int.TryParse(Attribute.Value, out Hold) || Hold < 0)
455 if (!
long.TryParse(Attribute.Value, out
long l) || l < 0)
461 Sid = Attribute.Value;
465 To = Attribute.
Value;
478 if (!
int.TryParse(Attribute.Value, out WaitSeconds) || Hold <= 0)
483 if (!
long.TryParse(Attribute.Value, out l))
495 Language = Attribute.Value;
499 if (Attribute.Value ==
"terminate")
504 Key = Attribute.Value;
508 NewKey = Attribute.Value;
512 Echo = Attribute.Value;
525 StringBuilder sb =
new StringBuilder();
528 if (
string.IsNullOrEmpty(Sid))
530 if (
string.IsNullOrEmpty(To) || !this.xmppServer.IsServerDomain(To,
true) || !(Key is
null))
537 Sid = this.xmppServer.GetRandomHexString(16);
539 while (sessions.ContainsKey(Sid));
541 if (WaitSeconds > MaxSecondsIdle)
542 WaitSeconds = MaxSecondsIdle;
544 int PollingSeconds = Math.Min(5, WaitSeconds);
545 int Requests = Hold + 1;
547 Session =
new BoshSession(
this, Sid, Rid, Version, From, To, Language, Hold, WaitSeconds, PollingSeconds, Requests,
548 Ack.HasValue && Ack.Value != 0, Secure, Request.
RemoteEndPoint.RemovePortNumber(), NewKey,
this.xmppServer);
549 sessions.Add(Sid, Session);
551 sb.Append(
"<body wait='");
552 sb.Append(WaitSeconds.ToString());
553 sb.Append(
"' inactivity='");
554 sb.Append(Math.Max(WaitSeconds / 2, 1).ToString());
555 sb.Append(
"' polling='");
556 sb.Append(PollingSeconds.ToString());
557 sb.Append(
"' requests='");
558 sb.Append(Requests.ToString());
559 sb.Append(
"' hold='");
560 sb.Append(Hold.ToString());
562 if (Ack.HasValue && Ack.Value != 0 && Rid.HasValue)
564 sb.Append(
"' ack='");
565 sb.Append(Rid.Value.ToString());
566 Session.RidReturnedLocked(Rid.Value);
571 sb.Append(
"' sid='");
573 sb.Append(
"' ver='");
575 sb.Append(
"' from='");
578 if (!
string.IsNullOrEmpty(Echo))
580 sb.Append(
"' echo='");
584 sb.Append(
"' xmlns='");
586 sb.Append(
"' xmlns:stream='");
587 sb.Append(XmppClientConnection.StreamNamespace);
592 sb.Append(
"</body>");
594 await this.Return(Response, sb.ToString());
598 if (!sessions.TryGetValue(Sid, out Session))
601 if (Session.RemoteEndPoint != Request.
RemoteEndPoint.RemovePortNumber())
604 if (Session.State ==
XmppConnectionState.Active && !
this.xmppServer.TouchClientConnection(Session.FullJid))
613 KeyOk = Session.CheckNextKey(Key);
620 await this.BoshError(Response,
"item-not-found");
624 if (!(NewKey is
null))
625 Session.Key = NewKey;
629 Session.Terminated =
true;
631 foreach (XmlNode N
in Body.ChildNodes)
633 if (N is XmlElement E && E.LocalName ==
"presence" &&
XML.
Attribute(E,
"type") ==
"unavailable")
634 Session.IsBound =
false;
637 await Session.DisposeAsync();
641 if (Session.Terminated)
642 await Session.DisposeAsync();
644 await Session.RegisterForResponse(XmppServer.Scheduler, Rid, Response, Echo);
650 internal Task BoshError(
HttpResponse Response,
string Condition)
652 StringBuilder Xml =
new StringBuilder();
654 Xml.Append(
"<body type='terminate");
656 if (!
string.IsNullOrEmpty(Condition))
658 Xml.Append(
"' condition='");
659 Xml.Append(Condition);
662 Xml.Append(
"' xmlns='");
666 return this.Return(Response, Xml.ToString());
669 internal static void Remove(BoshSession Session)
671 sessions.Remove(Session.Sid);
674 internal async Task Return(
HttpResponse Response,
string Xml)
676 byte[] Bin = Encoding.UTF8.GetBytes(Xml);
678 Response.ContentLength = Bin.Length;
682 await Response.
Write(
true, Bin);
688 this.httpServer.RequestResponded(Response.
Request, 500);
Helps with parsing of commong data types.
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static string Encode(string s)
Encodes a string for use in XML.
static XmlDocument ParseXml(string Xml)
Parses an XML Document from its string representation.
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.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
Stream Stream
Stream object currently being used.
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...
Base class for all asynchronous HTTP resources. An asynchronous resource responds outside of the meth...
Represents an HTTP request.
Stream DataStream
Data stream, if data is available, or null if data is not available.
HttpRequestHeader Header
Request header.
string RemoteEndPoint
Remote end-point.
bool HasData
If the request has data.
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...
HttpRequest Request
Corresponding HTTP Request
Task Write(byte[] Data)
Returns binary data in the response.
void SetHeader(string FieldName, string Value)
Sets a custom header field value.
BinaryTcpClient ClientConnection
Current client connection
Implements an HTTP server.
The server has not found anything matching the Request-URI. No indication is given of whether the con...
override bool HandlesSubPaths
If subpaths are handled.
Task GET(HttpRequest Request, HttpResponse Response)
Handles a GET requesst.
BoshWebClientResource(XmppServer XmppServer, HttpServer HttpServer, string ResourceName)
BOSH webclient interface
override bool UserSessions
If User session is requried
bool AllowsPOST
If POST method is allowed.
bool AllowsGET
If GET method is allowed.
async Task POST(HttpRequest Request, HttpResponse Response)
Handles a POST requesst.
const string HttpBindNamespace
http://jabber.org/protocol/httpbind
Represents a case-insensitive string.
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
Implements an in-memory cache.
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
GET Interface for HTTP resources.
POST Interface for HTTP resources.
XmppConnectionState
State of XMPP connection.
ContentType
DTLS Record content type.