5using System.Threading.Tasks;
37 private readonly
string userVariable;
38 private readonly
string[] userPrivileges;
51 HttpServer WebServer,
string UserVariable, params
string[] UserPrivileges)
55 this.nlClient = NLClient;
56 this.provider = Provider;
57 this.webServer = WebServer;
58 this.userVariable = UserVariable;
59 this.userPrivileges = UserPrivileges;
97 if (this.nlClient.ClientDisposed)
117 int i = s.IndexOf(
'/');
129 await Response.
SendResponse(
new ForbiddenException(Request,
"Access to block not granted: Accessing blocks can only be done by approved peers, or via the administrative portal."));
135 if (Session is
null ||
137 !(v.ValueObject is
IUser User))
144 foreach (
string Privilege
in this.userPrivileges)
146 if (!User.HasPrivilege(Privilege))
182 if (this.nlClient.ClientDisposed)
192 string FileName = this.provider.GetFullFileName(Ref.
FileName);
194 if (
string.IsNullOrEmpty(Ref.
FileName) || !File.Exists(FileName))
198 foreach (
string Source
in Ref.
Sources)
200 if (this.nlClient.ClientDisposed)
206 if (await this.nlClient.RetrieveBlock(Ref, Source,
null,
true))
217 FileName = this.provider.GetFullFileName(Ref.
FileName);
218 if (
string.IsNullOrEmpty(Ref.
FileName) || !File.Exists(FileName))
220 if (Ref.
Creator ==
this.provider.ExternalIdentity)
237 case "application/octet-stream":
238 Response.StatusCode = 200;
239 Response.StatusMessage =
"OK";
240 Response.ContentType = Alternative;
244 MemoryStream Header =
new MemoryStream();
245 int CollectionLen = f.ReadByte();
246 Header.WriteByte((
byte)CollectionLen);
248 if (CollectionLen == 0)
251 byte[] CollectionBin = await f.ReadAllAsync(CollectionLen);
253 Header.Write(CollectionBin, 0, CollectionLen);
255 string CollectionName = Encoding.UTF8.GetString(CollectionBin);
256 Response.
SetHeader(
"X-Collection", CollectionName);
258 int SigLen = f.ReadByte();
259 Header.WriteByte((
byte)SigLen);
264 byte[] Signature = await f.ReadAllAsync(SigLen);
266 Header.Write(Signature, 0, SigLen);
267 Response.
SetHeader(
"X-Signature", Convert.ToBase64String(Signature));
269 byte[] ContentLen = await f.ReadAllAsync(8);
271 Header.Write(ContentLen, 0, 8);
273 long InputLength = BitConverter.ToInt64(ContentLen, 0);
274 byte[] Buf = Header.ToArray();
276 Response.ContentLength = Header.Length + InputLength;
277 await Response.
Write(
true, Buf, 0, Buf.Length);
279 Buf =
new byte[(int)Math.Min(32768, InputLength)];
281 while (InputLength > 0)
283 int i = (int)Math.Min(32768, InputLength);
285 await f.ReadAllAsync(Buf, 0, i);
287 await Response.
Write(
false, Buf, 0, i);
296 StringBuilder Xml =
new StringBuilder();
297 XmlWriter w = XmlWriter.Create(Xml, Settings);
299 w.WriteStartDocument();
300 w.WriteStartElement(
"Block",
"http://waher.se/NLB");
301 w.WriteAttributeString(
"digest", Convert.ToBase64String(Ref.
Digest));
302 w.WriteAttributeString(
"status", Ref.
Status.ToString());
303 w.WriteAttributeString(
"signature", Convert.ToBase64String(Ref.
Signature));
304 w.WriteAttributeString(
"collection", Ref.
Collection);
306 w.WriteAttributeString(
"creator", Ref.
Creator);
308 if (Ref.
Expires != DateTime.MaxValue)
311 if (Ref.
Updated != DateTime.MinValue)
314 if (!(Ref.
Link is
null))
315 w.WriteAttributeString(
"link", Convert.ToBase64String(Ref.
Link));
321 while (await e.MoveNextAsync())
323 switch (e.CurrentEntry.Type)
326 w.WriteStartElement(
"Add");
330 w.WriteStartElement(
"Update");
334 w.WriteStartElement(
"Delete");
338 w.WriteStartElement(
"Clear");
339 w.WriteAttributeString(
"ts",
XML.
Encode(e.CurrentEntry.Timestamp));
349 w.WriteAttributeString(
"ts",
XML.
Encode(e.CurrentEntry.Timestamp));
350 w.WriteAttributeString(
"type", Obj.
TypeName);
351 w.WriteAttributeString(
"id", Obj.
ObjectId.ToString());
353 foreach (KeyValuePair<string, object> P
in Obj)
354 this.WriteProperty(w, P.Key, P.Value);
361 w.WriteEndDocument();
364 Response.StatusCode = 200;
365 Response.StatusMessage =
"OK";
366 Response.ContentType = Alternative;
367 await Response.
Write(Xml.ToString());
372 LinkedList<KeyValuePair<string, object>> Result =
new LinkedList<KeyValuePair<string, object>>();
374 Result.AddLast(
new KeyValuePair<string, object>(
"digest", Convert.ToBase64String(Ref.
Digest)));
375 Result.AddLast(
new KeyValuePair<string, object>(
"status", Ref.
Status.ToString()));
376 Result.AddLast(
new KeyValuePair<string, object>(
"signature", Convert.ToBase64String(Ref.
Signature)));
377 Result.AddLast(
new KeyValuePair<string, object>(
"collection", Ref.
Collection));
378 Result.AddLast(
new KeyValuePair<string, object>(
"created",
XML.
Encode(Ref.
Created)));
379 Result.AddLast(
new KeyValuePair<string, object>(
"creator", Ref.
Creator));
381 if (Ref.
Expires != DateTime.MaxValue)
382 Result.AddLast(
new KeyValuePair<string, object>(
"expires",
XML.
Encode(Ref.
Expires)));
384 if (Ref.
Updated != DateTime.MinValue)
385 Result.AddLast(
new KeyValuePair<string, object>(
"updated",
XML.
Encode(Ref.
Updated)));
387 if (!(Ref.
Link is
null))
388 Result.AddLast(
new KeyValuePair<string, object>(
"link", Convert.ToBase64String(Ref.
Link)));
390 LinkedList<object> Entries =
new LinkedList<object>();
391 Result.AddLast(
new KeyValuePair<string, object>(
"entries", Entries));
397 while (await e.MoveNextAsync())
399 LinkedList<KeyValuePair<string, object>> P1 =
new LinkedList<KeyValuePair<string, object>>();
401 P1.AddLast(
new KeyValuePair<string, object>(
"type", e.CurrentEntry.Type.ToString()));
402 P1.AddLast(
new KeyValuePair<string, object>(
"ts",
XML.
Encode(e.CurrentEntry.Timestamp)));
404 switch (e.CurrentEntry.Type)
409 LinkedList<KeyValuePair<string, object>> P2 =
new LinkedList<KeyValuePair<string, object>>();
412 P1.AddLast(
new KeyValuePair<string, object>(
"obj", P2));
414 P2.AddLast(
new KeyValuePair<string, object>(
"type", Obj.TypeName));
415 P2.AddLast(
new KeyValuePair<string, object>(
"id", Obj.ObjectId.ToString()));
417 foreach (KeyValuePair<string, object> P
in Obj)
418 P2.AddLast(
new KeyValuePair<string, object>(P.Key, P.Value));
427 Response.StatusCode = 200;
428 Response.StatusMessage =
"OK";
429 Response.ContentType = Alternative;
434 await Response.
SendResponse(
new NotAcceptableException(
"Desired format not acceptable. Use the Accept header field to select either text/xml, application/json or application/octet-stream."));
446 private void WriteProperty(XmlWriter w,
string Name,
object Value)
450 w.WriteStartElement(
"Null");
452 w.WriteAttributeString(
"n",
string.Empty, Name);
455 else if (Value is Enum)
457 w.WriteStartElement(
"En");
459 w.WriteAttributeString(
"n",
string.Empty, Name);
460 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
465 switch (Type.GetTypeCode(Value.GetType()))
467 case TypeCode.Boolean:
468 w.WriteStartElement(
"Bl");
470 w.WriteAttributeString(
"n",
string.Empty, Name);
476 w.WriteStartElement(
"B");
478 w.WriteAttributeString(
"n",
string.Empty, Name);
479 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
484 w.WriteStartElement(
"Ch");
486 w.WriteAttributeString(
"n",
string.Empty, Name);
487 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
491 case TypeCode.DateTime:
492 w.WriteStartElement(
"DT");
494 w.WriteAttributeString(
"n",
string.Empty, Name);
495 w.WriteAttributeString(
"v",
string.Empty,
XML.
Encode((DateTime)Value));
499 case TypeCode.Decimal:
500 w.WriteStartElement(
"Dc");
502 w.WriteAttributeString(
"n",
string.Empty, Name);
507 case TypeCode.Double:
508 w.WriteStartElement(
"Db");
510 w.WriteAttributeString(
"n",
string.Empty, Name);
516 w.WriteStartElement(
"I2");
518 w.WriteAttributeString(
"n",
string.Empty, Name);
519 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
524 w.WriteStartElement(
"I4");
526 w.WriteAttributeString(
"n",
string.Empty, Name);
527 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
532 w.WriteStartElement(
"I8");
534 w.WriteAttributeString(
"n",
string.Empty, Name);
535 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
540 w.WriteStartElement(
"I1");
542 w.WriteAttributeString(
"n",
string.Empty, Name);
543 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
547 case TypeCode.Single:
548 w.WriteStartElement(
"Fl");
550 w.WriteAttributeString(
"n",
string.Empty, Name);
555 case TypeCode.String:
556 string s = Value.ToString();
559 XmlConvert.VerifyXmlChars(s);
560 w.WriteStartElement(
"S");
562 w.WriteAttributeString(
"n",
string.Empty, Name);
563 w.WriteAttributeString(
"v",
string.Empty, s);
568 byte[] Bin = Encoding.UTF8.GetBytes(s);
569 s = Convert.ToBase64String(Bin);
570 w.WriteStartElement(
"S64");
572 w.WriteAttributeString(
"n",
string.Empty, Name);
573 w.WriteAttributeString(
"v",
string.Empty, s);
578 case TypeCode.UInt16:
579 w.WriteStartElement(
"U2");
581 w.WriteAttributeString(
"n",
string.Empty, Name);
582 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
586 case TypeCode.UInt32:
587 w.WriteStartElement(
"U4");
589 w.WriteAttributeString(
"n",
string.Empty, Name);
590 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
594 case TypeCode.UInt64:
595 w.WriteStartElement(
"U8");
597 w.WriteAttributeString(
"n",
string.Empty, Name);
598 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
602 case TypeCode.DBNull:
604 w.WriteStartElement(
"Null");
606 w.WriteAttributeString(
"n",
string.Empty, Name);
610 case TypeCode.Object:
611 if (Value is TimeSpan)
613 w.WriteStartElement(
"TS");
615 w.WriteAttributeString(
"n",
string.Empty, Name);
616 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
619 else if (Value is DateTimeOffset DTO)
621 w.WriteStartElement(
"DTO");
623 w.WriteAttributeString(
"n",
string.Empty, Name);
624 w.WriteAttributeString(
"v",
string.Empty,
XML.
Encode(DTO));
632 XmlConvert.VerifyXmlChars(s);
633 w.WriteStartElement(
"CIS");
635 w.WriteAttributeString(
"n",
string.Empty, Name);
636 w.WriteAttributeString(
"v",
string.Empty, s);
641 byte[] Bin = Encoding.UTF8.GetBytes(s);
642 s = Convert.ToBase64String(Bin);
643 w.WriteStartElement(
"CIS64");
645 w.WriteAttributeString(
"n",
string.Empty, Name);
646 w.WriteAttributeString(
"v",
string.Empty, s);
650 else if (Value is
byte[] Bin)
652 w.WriteStartElement(
"Bin");
654 w.WriteAttributeString(
"n",
string.Empty, Name);
672 if (i == 0 && j == c)
679 Buffer.BlockCopy(Bin, i, Buf, 0, j);
681 w.WriteElementString(
"Chunk", Convert.ToBase64String(Buf, 0, j, Base64FormattingOptions.None));
687 else if (Value is Guid)
689 w.WriteStartElement(
"ID");
691 w.WriteAttributeString(
"n",
string.Empty, Name);
692 w.WriteAttributeString(
"v",
string.Empty, Value.ToString());
695 else if (Value is Array A)
697 w.WriteStartElement(
"Array");
699 w.WriteAttributeString(
"n",
string.Empty, Name);
700 w.WriteAttributeString(
"elementType",
string.Empty, Value.GetType().GetElementType().FullName);
702 foreach (
object Obj
in A)
703 this.WriteProperty(w,
null, Obj);
709 w.WriteStartElement(
"Obj");
711 w.WriteAttributeString(
"n",
string.Empty, Name);
712 w.WriteAttributeString(
"type",
string.Empty, Obj.TypeName);
714 foreach (KeyValuePair<string, object> P
in Obj)
715 this.WriteProperty(w, P.Key, P.Value);
720 throw new Exception(
"Unhandled property value type: " + Value.GetType().FullName);
724 throw new Exception(
"Unhandled property value type: " + Value.GetType().FullName);
Static class that does BASE64URL encoding (using URL and filename safe alphabet), as defined in RFC46...
static byte[] Decode(string Base64Url)
Converts a Base64URL-encoded string to its binary representation.
Helps with parsing of commong data types.
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Helps with common JSON-related tasks.
static string Encode(string s)
Encodes a string for inclusion in JSON.
const string DefaultContentType
application/json
const string DefaultContentType
Default content type for XML documents.
const string SchemaContentType
Default content type for XML schema documents.
Helps with common XML-related tasks.
static string Encode(string s)
Encodes a string for use in XML.
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repe...
The request failed due to failure of a previous request (e.g., a PROPPATCH).
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.
HttpRequestHeader Header
Request header.
string RemoteEndPoint
Remote end-point.
string SubPath
Sub-path. If a resource is found handling the request, this property contains the trailing sub-path o...
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"
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...
Task Write(byte[] Data)
Returns binary data in the response.
void SetHeader(string FieldName, string Value)
Sets a custom header field value.
Implements an HTTP server.
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...
Provides authenticated and authorized clients with binary blocks.
override bool HandlesSubPaths
If the resource handles sub-paths.
async Task GET(HttpRequest Request, HttpResponse Response)
Executes the GET method on the resource.
const string ErrorMsg_BlockFileHasBeenRemoved
Block file has been removed.
bool AllowsGET
If the GET method is allowed.
async Task ProcessRequest(HttpFieldAccept Accept, HttpResponse Response, BlockReference Ref)
Processes a block request.
BlockResource(string ResourceName, NeuroLedgerProvider Provider, XmppClient Client, NeuroLedgerClient NLClient, HttpServer WebServer, string UserVariable, params string[] UserPrivileges)
Provides authenticated and authorized clients with binary blocks.
override bool UserSessions
If the resource uses user sessions.
Maintains information about an item in the roster.
bool IsInGroup(string Group)
Checks if the roster item is in a specific group.
SubscriptionState State
roup Current subscription state.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Represents a case-insensitive string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static async Task Delete(object Object)
Deletes an object in the database.
Reads objects in a block.
static Stream GetStream(string FileName, NeuroLedgerProvider Provider)
Gets a stream to the contents of the block.
static Task< BlockReference > FindReference(byte[] Digest)
Finds a BlockReference object related to a block, given its digest.
Enumeratres through objects available in a series of blocks.
static async Task< ObjectEnumerator< T > > Create(IAsyncEnumerator< BlockReference > BlockEnumerator, NeuroLedgerProvider Provider)
Creates an object enumerator from a block enumerator.
Contains a reference to a block in the ledger.
bool AccessDenied
If access to the block was denied.
string[] Sources
Sources of block
byte[] Digest
Digest of block
byte[] Signature
Signature of block
string FileName
Local filename of block
Generic object. Contains a sequence of properties.
string TypeName
Type name.
Contains information about a variable.
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
GET Interface for HTTP resources.
Basic interface for a user.
SubscriptionState
State of a presence subscription.
EntryType
Ledger entry type.