Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 55 additions & 17 deletions src/Opc.Ua.Bindings.Https/Https/HttpsTransportListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,9 +1210,26 @@ await WriteResponseAsync(context.Response, message, HttpStatusCode.BadRequest)
return;
}

IServiceRequest input = BinaryDecoder.DecodeMessage<IServiceRequest>(
buffer,
m_quotas.MessageContext);
IServiceRequest input;
try
{
input = BinaryDecoder.DecodeMessage<IServiceRequest>(
buffer,
m_quotas.MessageContext);
}
catch (ServiceResultException sre)
{
// Report a request the decoder rejected (for example a string
// above MaxStringLength) as a ServiceFault that echoes its
// RequestHandle (OPC 10000-4 §7.33).
IServiceResponse decodeFault = EndpointBase.CreateFault(
m_logger,
null,
sre,
RequestHandleReader.FromBinary(buffer));
await WriteServiceResponseAsync(context, decodeFault, ct).ConfigureAwait(false);
return;
}

if (m_mutualTlsEnabled && input.TypeId == DataTypeIds.CreateSessionRequest)
{
Expand Down Expand Up @@ -1301,7 +1318,7 @@ await WriteResponseAsync(
{
IServiceResponse serviceResponse = EndpointBase.CreateFault(
m_logger,
null,
input,
serviceResultException);
await WriteServiceResponseAsync(context, serviceResponse, ct)
.ConfigureAwait(false);
Expand Down Expand Up @@ -1388,18 +1405,23 @@ await WriteResponseAsync(
}

IServiceRequest input;
byte[]? payload = null;
try
{
input = await JsonRequestMapper
.DecodeRequestAsync(context.Request.Body, m_quotas.MessageContext, ct)
payload = await JsonRequestMapper
.ReadAllBoundedAsync(context.Request.Body, m_quotas.MessageContext.MaxMessageSize, ct)
.ConfigureAwait(false);
input = JsonRequestMapper.DecodeRequest(payload, m_quotas.MessageContext);
}
catch (ServiceResultException sre)
{
// echo the RequestHandle of a request that could not be
// decoded (OPC 10000-4 §7.33).
IServiceResponse fault = EndpointBase.CreateFault(
m_logger,
null,
sre);
sre,
payload == null ? 0 : RequestHandleReader.FromJson(payload));
await WriteJsonResponseAsync(context, fault, ct).ConfigureAwait(false);
return;
}
Expand Down Expand Up @@ -1432,7 +1454,7 @@ await WriteResponseAsync(
// for discovery services (Part 4 §5.4 / §5.5).
IServiceResponse discoveryFault = EndpointBase.CreateFault(
m_logger,
null,
input,
new ServiceResultException(
StatusCodes.BadSecurityPolicyRejected,
"Channel can only be used for discovery."));
Expand Down Expand Up @@ -1889,10 +1911,10 @@ await ws.CloseAsync(
while (!completed);

IServiceResponse responseToSend;
byte[] messageBytes = new byte[totalRead];
Buffer.BlockCopy(receiveBuffer, 0, messageBytes, 0, totalRead);
try
{
byte[] messageBytes = new byte[totalRead];
Buffer.BlockCopy(receiveBuffer, 0, messageBytes, 0, totalRead);
IServiceRequest request = JsonDecoder.DecodeMessage<IServiceRequest>(
messageBytes,
m_quotas.MessageContext);
Expand All @@ -1904,7 +1926,7 @@ await ws.CloseAsync(
// when no MessageSecurityMode.None JSON endpoint matches.
responseToSend = EndpointBase.CreateFault(
m_logger,
null,
request,
new ServiceResultException(
StatusCodes.BadSecurityPolicyRejected,
"Channel can only be used for discovery."));
Expand All @@ -1918,12 +1940,20 @@ await ws.CloseAsync(
}
catch (ServiceResultException sre)
{
responseToSend = EndpointBase.CreateFault(m_logger, null, sre);
responseToSend = EndpointBase.CreateFault(
m_logger,
null,
sre,
RequestHandleReader.FromJson(messageBytes));
}
catch (Exception ex)
{
m_logger.ErrorProcessingJsonRequest(ex);
responseToSend = EndpointBase.CreateFault(m_logger, null, ex);
responseToSend = EndpointBase.CreateFault(
m_logger,
null,
ex,
RequestHandleReader.FromJson(messageBytes));
}

byte[] responseBytes = JsonRequestMapper.EncodeResponse(
Expand Down Expand Up @@ -2102,10 +2132,10 @@ await ws.CloseAsync(
while (!completed);

IServiceResponse responseToSend;
byte[] messageBytes = new byte[totalRead];
Buffer.BlockCopy(receiveBuffer, 0, messageBytes, 0, totalRead);
try
{
byte[] messageBytes = new byte[totalRead];
Buffer.BlockCopy(receiveBuffer, 0, messageBytes, 0, totalRead);
IServiceRequest request = JsonDecoder.DecodeMessage<IServiceRequest>(
messageBytes,
m_quotas.MessageContext);
Expand All @@ -2117,12 +2147,20 @@ await ws.CloseAsync(
}
catch (ServiceResultException sre)
{
responseToSend = EndpointBase.CreateFault(m_logger, null, sre);
responseToSend = EndpointBase.CreateFault(
m_logger,
null,
sre,
RequestHandleReader.FromJson(messageBytes));
}
catch (Exception ex)
{
m_logger.ErrorProcessingOpenApiRequest(ex);
responseToSend = EndpointBase.CreateFault(m_logger, null, ex);
responseToSend = EndpointBase.CreateFault(
m_logger,
null,
ex,
RequestHandleReader.FromJson(messageBytes));
}

byte[] responseBytes = JsonRequestMapper.EncodeResponse(
Expand Down
15 changes: 15 additions & 0 deletions src/Opc.Ua.Bindings.Https/Https/JsonRequestMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ public static async ValueTask<IServiceRequest> DecodeRequestAsync(
byte[] payload = await ReadAllBoundedAsync(body, context.MaxMessageSize, ct)
.ConfigureAwait(false);

return DecodeRequest(payload, context);
}

/// <summary>
/// Decodes a single OPC UA service request from a JSON message payload.
/// </summary>
/// <param name="payload">The UTF-8 encoded message.</param>
/// <param name="context">The encoding context.</param>
/// <returns>The decoded service request.</returns>
/// <exception cref="ServiceResultException">
/// Thrown with <see cref="StatusCodes.BadDecodingError"/> if the payload
/// is malformed or not a recognized OPC UA JSON service request.
/// </exception>
internal static IServiceRequest DecodeRequest(byte[] payload, IServiceMessageContext context)
{
try
{
return JsonDecoder.DecodeMessage<IServiceRequest>(payload, context);
Expand Down
32 changes: 24 additions & 8 deletions src/Opc.Ua.Core/Stack/Server/EndpointBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,20 +408,36 @@ protected ServiceFault CreateFault(IServiceRequest? request, Exception exception
/// <param name="exception">The exception.</param>
/// <returns>A fault message.</returns>
public static ServiceFault CreateFault(ILogger logger, IServiceRequest? request, Exception exception)
{
return CreateFault(logger, request, exception, requestHandle: 0);
}

/// <summary>
/// Creates a fault message.
/// </summary>
/// <param name="logger">A contextual logger to log to</param>
/// <param name="request">The request, or <c>null</c> if it could not be decoded.</param>
/// <param name="exception">The exception.</param>
/// <param name="requestHandle">The RequestHandle to echo when <paramref name="request"/>
/// is <c>null</c>, for example as read by <see cref="RequestHandleReader"/> from a
/// message that could not be decoded (OPC 10000-4 §7.33); 0 if it is unknown.</param>
/// <returns>A fault message.</returns>
internal static ServiceFault CreateFault(
ILogger logger,
IServiceRequest? request,
Exception exception,
uint requestHandle)
{
DiagnosticsMasks diagnosticsMask = DiagnosticsMasks.ServiceNoInnerStatus;

var fault = new ServiceFault();

if (request != null)
{
fault.ResponseHeader.Timestamp = DateTime.UtcNow;
fault.ResponseHeader.RequestHandle = request.RequestHeader.RequestHandle;
fault.ResponseHeader.Timestamp = DateTime.UtcNow;
fault.ResponseHeader.RequestHandle = request?.RequestHeader?.RequestHandle ?? requestHandle;

if (request.RequestHeader != null)
{
diagnosticsMask = (DiagnosticsMasks)request.RequestHeader.ReturnDiagnostics;
}
if (request?.RequestHeader != null)
{
diagnosticsMask = (DiagnosticsMasks)request.RequestHeader.ReturnDiagnostics;
}

ServiceResult result;
Expand Down
Loading
Loading