public void Write(IRemoraOperation operation, IUniversalResponse response) { if (operation == null) throw new ArgumentNullException("operation"); if (response == null) throw new ArgumentNullException("response"); Contract.EndContractBlock(); if (operation.OnError) { Logger.ErrorFormat(operation.Exception, "There has been an error when processing request coming from {0}.", operation.IncomingUri); _exceptionformatter.WriteException(operation, response); } else { response.StatusCode = operation.Response.StatusCode; foreach (var header in operation.Response.HttpHeaders) { response.SetHeader(header.Key, header.Value); } if (operation.Response.Data != null) { response.OutputStream.Write(operation.Response.Data, 0, operation.Response.Data.Length); } response.OutputStream.Flush(); } }
public SerializableOperation(IRemoraOperation operation) { if (operation == null) throw new ArgumentNullException("operation"); Contract.EndContractBlock(); OperationId = operation.OperationId; IncomingUri = operation.IncomingUri != null ? operation.IncomingUri.ToString() : null; Kind = operation.Kind; OnError = operation.OnError; if (operation.Exception != null) { ExceptionType = operation.Exception.GetType().AssemblyQualifiedName; ExceptionMessage = operation.Exception.ToString(); } if (operation.Request != null) Request = new SerializableRequest(operation.Request); if (operation.Response != null) Response = new SerializableResponse(operation.Response); CreatedAtUtc = operation.CreatedAtUtc; if (operation.ExecutingPipeline != null) { PipelineName = operation.ExecutingPipeline.Id; if (operation.ExecutingPipeline.Definition != null) PipelineComponents = string.Join(",", operation.ExecutingPipeline.Definition.ComponentDefinitions.Select( x => x.RefId)); } }
public override void EndAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action callback) { if (operation.Kind == RemoraOperationKind.Soap) { EndRecordSoapOperation(operation, componentDefinition); } callback(); }
public override void EndAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action callback) { try { TraceOperation(operation, componentDefinition); } catch (Exception ex) { Logger.WarnFormat(ex, "There has been an error while tracing operation {0}.", operation); } callback(); }
protected virtual void WriteSoap(IRemoraOperation operation, IUniversalResponse response) { response.ContentType = "text/xml"; response.StatusCode = (int) HttpStatusCode.OK; response.ContentEncoding = Encoding.UTF8; var content = response.ContentEncoding.GetBytes(string.Format(ErrorResources.SoapError, operation.Exception.GetType().Name.Replace( "Exception", ""), operation.Exception.Message)); response.OutputStream.Write(content, 0, content.Length); response.OutputStream.Flush(); }
public override void BeginAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action<bool> callback) { if (operation.Kind == RemoraOperationKind.Soap) { RecordSoapOperation(operation); } else { Logger.WarnFormat("Unable to record operation {0} because it appears to not be a soap request.", operation); } callback(true); }
public void WriteException(IRemoraOperation operation, IUniversalResponse response) { if (operation == null) throw new ArgumentNullException("operation"); if (response == null) throw new ArgumentNullException("response"); Contract.EndContractBlock(); switch (operation.Kind) { case RemoraOperationKind.Soap: WriteSoap(operation, response); break; default: WriteHtmlException(operation.Exception, response); break; } }
public override void BeginAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action<bool> callback) { var category = GetCategory(componentDefinition); var executionPropertyKey = GetStopwatchExecutionPropertyKey(category); if (operation.ExecutionProperties.ContainsKey(executionPropertyKey)) { Logger.WarnFormat( "There may exists two tracer with the same category ({0}) in the same pipeline. Results may be inacurate.", category); } var stopwatch = new Stopwatch(); stopwatch.Start(); operation.ExecutionProperties[executionPropertyKey] = stopwatch; callback(true); }
public override void BeginAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action<bool> callback) { if (operation == null) throw new ArgumentNullException("operation"); if (componentDefinition == null) throw new ArgumentNullException("componentDefinition"); if (callback == null) throw new ArgumentNullException("callback"); Contract.EndContractBlock(); switch (operation.Kind) { case RemoraOperationKind.Soap: PlaySoapOperation(operation, componentDefinition); break; default: throw new SoapPlayerException( string.Format("Unable to playback operation {0} because it is not a soap operation.", operation)); } callback(false); }
public RemoraOperationKind Identify(IRemoraOperation operation) { if (operation == null) throw new ArgumentNullException("operation"); Contract.EndContractBlock(); if (Logger.IsDebugEnabled) Logger.DebugFormat("Identifying operation {0}...", operation); if (operation.Request.HttpHeaders.ContainsKey("SOAPAction")) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0} is kind of {1}.", operation, RemoraOperationKind.Soap); return RemoraOperationKind.Soap; } if (Logger.IsDebugEnabled) Logger.DebugFormat("Unable to identify operation {0}.", operation); return RemoraOperationKind.Unknown; }
protected virtual void SetHttpHeaders(IRemoraOperation operation, HttpWebRequest webRequest) { foreach (var header in operation.Request.HttpHeaders) { switch (header.Key.Trim().ToLowerInvariant()) { case "accept": webRequest.Accept = header.Value; break; case "connection": break; case "content-length": break; case "content-type": webRequest.ContentType = header.Value; break; case "expect": break; case "date": DateTime dateValue; if (DateTime.TryParse(header.Value, out dateValue)) webRequest.Date = dateValue; break; case "host": if ((operation.ExecutingPipeline != null) && (operation.ExecutingPipeline.Definition != null) && (operation.ExecutingPipeline.Definition.Properties.ContainsKey("doNotAlterHost")) && (operation.ExecutingPipeline.Definition.Properties["doNotAlterHost"].Equals("true", StringComparison . InvariantCultureIgnoreCase)) ) { webRequest.Host = header.Value; } else { webRequest.Host = operation.Request.Uri.Host; } break; case "if-modified-since": DateTime ifModifiedSinceValue; if (DateTime.TryParse(header.Value, out ifModifiedSinceValue)) webRequest.IfModifiedSince = ifModifiedSinceValue; break; case "range": break; case "referer": webRequest.Referer = header.Value; break; case "transfer-encoding": break; case "user-agent": webRequest.UserAgent = header.Value; break; default: try { webRequest.Headers.Add(header.Key, header.Value); } catch (Exception ex) { Logger.ErrorFormat(ex, "Error while setting header {0}={1}", header.Key, header.Value); throw; } break; } } }
private void EndRecordSoapOperation(IRemoraOperation operation, IComponentDefinition componentDefinition) { if (!operation.ExecutionProperties.ContainsKey(SoapActionKey)) return; var soapActionName = (string) operation.ExecutionProperties[SoapActionKey]; if (!componentDefinition.Properties.ContainsKey("directory")) { Logger.WarnFormat( "Unable to record operation {0}: no directory has been provided. You must use the directory attribute in the component configuration.", operation); return; } var directoryPath = componentDefinition.Properties["directory"]; if (!Directory.Exists(directoryPath)) { try { Directory.CreateDirectory(directoryPath); } catch (Exception ex) { Logger.WarnFormat(ex, "Unable to record operation {0}: the directory {1} does not exists and there has been an error when creating it.", operation, directoryPath); return; } } var randomAppendToFileName = Path.GetFileNameWithoutExtension(Path.GetRandomFileName()); var fileName = Path.Combine(directoryPath, string.Format("{0}.{1}.xml", soapActionName.MakeValidFileName(), randomAppendToFileName)); if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: saving record for {1} in {2}...", operation, soapActionName, fileName); var serializableOperation = new SerializableOperation(operation); try { using (var writeStream = File.OpenWrite(fileName)) { serializableOperation.Serialize(writeStream); } if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: successfully recorded in {1}.", operation, fileName); } catch (Exception ex) { Logger.WarnFormat(ex, "There has been an error while saving record file {0} for operation {1}.", fileName, operation); } }
private void RecordSoapOperation(IRemoraOperation operation) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Recording operation {0} as soap...", operation); if (!operation.Request.HttpHeaders.ContainsKey("SOAPAction")) { Logger.WarnFormat("Unable to record operation {0} because it doesn't have a SOAPAction header.", operation); return; } operation.ExecutionProperties[SoapActionKey] = operation.Request.HttpHeaders["SOAPAction"]; }
protected virtual void WriteData(IRemoraOperation operation, HttpWebRequest webRequest) { if (operation.Request.Data != null) { webRequest.ContentLength = operation.Request.Data.Length; using (var requestStream = webRequest.GetRequestStream()) { requestStream.Write(operation.Request.Data, 0, operation.Request.Data.Length); } } else { webRequest.ContentLength = 0; } }
public override void BeginAsyncProcess(IRemoraOperation operation, IComponentDefinition componentDefinition, Action<bool> callback) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Preparing to send {0}...", operation); if (operation.Request.Uri == null) { throw new UnknownDestinationException( string.Format( "Unable to send {0}: no destination uri is defined. Either use a rewrite attribute on the pipeline or create a custom IPipelineComponent that will determine the destination uri.", operation)); } if (!HttpSchemeRx.IsMatch(operation.Request.Uri.Scheme)) { throw new InvalidDestinationUriException( string.Format( "The destination uri for {0} is not a valid uri: {1}. Remora supports only http(s) destinations.", operation, operation.Request.Uri)); } var webRequest = (HttpWebRequest) WebRequest.Create(operation.Request.Uri); if ((operation.ExecutingPipeline != null) && (operation.ExecutingPipeline.Definition != null) && (!string.IsNullOrEmpty(operation.ExecutingPipeline.Definition.ClientCertificateFilePath)) ) { ManageCertificate(webRequest, operation.ExecutingPipeline.Definition.ClientCertificateFilePath, operation.ExecutingPipeline.Definition.ClientCertificatePassword); } webRequest.Method = operation.Request.Method ?? "POST"; SetHttpHeaders(operation, webRequest); if (webRequest.Method.ToLowerInvariant() != "get") { WriteData(operation, webRequest); } else { webRequest.ContentLength = 0; } webRequest.BeginGetResponse((result) => { webRequest = (HttpWebRequest) result.AsyncState; try { var response = (HttpWebResponse) webRequest.EndGetResponse(result); ReadResponse(operation, response, componentDefinition); if (Logger.IsDebugEnabled) Logger.DebugFormat( "Successfully received response from {0} for {1}.", webRequest.RequestUri, operation); } catch (WebException webEx) { if (webEx.Status == WebExceptionStatus.ProtocolError) { ReadResponse(operation, (HttpWebResponse) webEx.Response, componentDefinition); if (Logger.IsDebugEnabled) Logger.DebugFormat( "Successfully received response from {0} for {1}.", webRequest.RequestUri, operation); } else { var message = string.Format( "There has been an error while sending {0} to {1}.", operation, webRequest.RequestUri); Logger.Error(message, webEx); operation.Exception = new SendException(message, webEx); } } catch (Exception ex) { var message = string.Format( "There has been an error while sending {0} to {1}.", operation, webRequest.RequestUri); Logger.Error(message, ex); operation.Exception = new SendException(message, ex); } finally { callback(false); } }, webRequest); }
public void EngineCallback(IRemoraOperation operation) { if (_logger.IsDebugEnabled) _logger.DebugFormat("Async process ended for request coming from {0}. Writing results...", IncomingUri); IUniversalResponse universalResponse = null; switch (_kind) { case ContextKind.Web: universalResponse = new UniversalResponse(HttpWebContext.Response); break; case ContextKind.Net: universalResponse = new UniversalResponse(HttpListenerContext.Response); break; } var writer = _container.Resolve<IResponseWriter>(); writer.Write(operation, universalResponse); IsCompleted = true; _callback(this); }
private void PlaySoapOperation(IRemoraOperation operation, IComponentDefinition componentDefinition) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Trying to reply with a mock for {0}...", operation); if (!componentDefinition.Properties.ContainsKey("directory")) { throw new SoapPlayerException( "Unable to playback because no directory has been provided. Please specify a source directory in the component definition."); } var directoryPath = componentDefinition.Properties["directory"]; if (!operation.Request.HttpHeaders.ContainsKey("SOAPAction")) { throw new SoapPlayerException( string.Format("Unable to playback operation {0} because it doesn't have a SOAPAction header.", operation)); } var soapAction = operation.Request.HttpHeaders["SOAPAction"]; IEnumerable<string> candidateFiles; try { candidateFiles = Directory.EnumerateFiles(directoryPath, soapAction.MakeValidFileName() + ".*"); } catch (Exception ex) { throw new SoapPlayerException( string.Format("There has been an error while enumerating files in {0}", directoryPath), ex); } var requestDoc = _soapTransformer.LoadSoapDocument(operation.Request).Normalize(); foreach (var candidateFile in candidateFiles) { try { if (Logger.IsDebugEnabled) Logger.DebugFormat("Opening file {0}...", candidateFile); SerializableOperation serializableOperation; using (var readStream = File.OpenRead(candidateFile)) { serializableOperation = SerializableOperation.Deserialize(readStream); if (MockMatch(serializableOperation, requestDoc, componentDefinition)) { if (Logger.IsInfoEnabled) Logger.InfoFormat("Found appropriate mock for {0}: {1}.", operation, candidateFile); operation.Response.ContentEncoding = Encoding.GetEncoding(serializableOperation.Response.ContentEncoding); foreach (var header in serializableOperation.Response.Headers) { operation.Response.HttpHeaders.Add(header.Name, header.Value); } operation.Response.StatusCode = serializableOperation.Response.StatusCode; operation.Response.Data = serializableOperation.Response.GetData(); return; } } } catch (Exception ex) { throw new SoapPlayerException(string.Format("Error while opening mock file {0}.", candidateFile), ex); } } throw new SoapPlayerException( string.Format("Unable to find appropriate mock for operation {0} in directory {1}.", operation, directoryPath)); }
public IPipeline Get(IRemoraOperation operation) { if (operation == null) throw new ArgumentNullException("operation"); Contract.EndContractBlock(); if (Logger.IsDebugEnabled) Logger.DebugFormat("Finding appropriate pipeline for {0}...", operation.IncomingUri); if (_config.PipelineDefinitions != null) { foreach (var pipelineDef in _config.PipelineDefinitions) { Regex regex; try { regex = new Regex(pipelineDef.UriFilterRegex, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); } catch (Exception ex) { throw new InvalidConfigurationException( string.Format( "There has been an error while initializing the regular expression for pipeline {0}: {1}", pipelineDef.Id, pipelineDef.UriFilterRegex), ex); } if (regex.IsMatch(operation.IncomingUri.ToString())) { if (Logger.IsDebugEnabled) Logger.DebugFormat( "Found pipeline definition {0} (filter: {1}) for {2}. Creating IPipeline...", pipelineDef.Id, pipelineDef.UriFilterRegex, operation.IncomingUri); var components = new List<IPipelineComponent>(); foreach (var componentDef in pipelineDef.ComponentDefinitions) { try { components.Add(_kernel.Resolve<IPipelineComponent>(componentDef.RefId)); } catch (Exception ex) { throw new InvalidConfigurationException( string.Format( "There has been an error while trying to resolve component with id {0} referenced in pipeline {1}. Maybe it is not referenced in castle or its parameters are inapproriate (check the service type, it must be IPipelineComponent).", componentDef.RefId, pipelineDef.Id), ex); } } if (Logger.IsDebugEnabled) Logger.DebugFormat("Pipeline {0} created for {1}.", pipelineDef.Id, operation.IncomingUri); if (!string.IsNullOrWhiteSpace(pipelineDef.UriRewriteRegex)) { try { operation.Request.Uri = new Uri(regex.Replace(operation.IncomingUri.ToString(), pipelineDef.UriRewriteRegex)); if (Logger.IsDebugEnabled) Logger.DebugFormat("Wrote outgoing uri for {0}: {1}.", operation.IncomingUri, operation.Request.Uri); } catch (Exception ex) { throw new UrlRewriteException( string.Format( "There has been an error while rewriting uri {0} with filter {1} and rewrite {2}.", operation.IncomingUri, pipelineDef.UriFilterRegex, pipelineDef.UriRewriteRegex), ex); } } var pipeline = new Pipeline(pipelineDef.Id, components, pipelineDef); operation.ExecutingPipeline = pipeline; return pipeline; } else { if (Logger.IsDebugEnabled) Logger.DebugFormat("Skipped pipeline definition {0} (filter: {1}) for {2}.", pipelineDef.Id, pipelineDef.UriFilterRegex, operation.IncomingUri); } } } return null; }
protected virtual void ReadResponse(IRemoraOperation operation, HttpWebResponse response, IComponentDefinition componentDefinition) { operation.Response.StatusCode = (int) response.StatusCode; operation.Response.Uri = response.ResponseUri; foreach (var header in response.Headers.AllKeys) { operation.Response.HttpHeaders.Add(header, response.Headers[header]); } using (var stream = response.GetResponseStream()) { operation.Response.Data = stream.ReadFully(_config.MaxMessageSize); } ReadEncoding(operation, response, componentDefinition); }
private void TraceOperation(IRemoraOperation operation, IComponentDefinition componentDefinition) { var category = GetCategory(componentDefinition); if (!componentDefinition.Properties.ContainsKey("directory")) { Logger.WarnFormat( "Unable to trace operation {0}: no directory has been provided. You must use the directory attribute in the component configuration.", operation); return; } var directoryPath = componentDefinition.Properties["directory"]; if (!Directory.Exists(directoryPath)) { try { Directory.CreateDirectory(directoryPath); } catch (Exception ex) { Logger.WarnFormat(ex, "Unable to trace operation {0}: the directory {1} does not exists and there has been an error when creating it.", operation, directoryPath); return; } } var fileName = Path.Combine(directoryPath, string.Format("{0}-{1}-{2}.xml", DateTime.UtcNow.ToString("s").MakeValidFileName(), category.MakeValidFileName(), operation.OperationId)); if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: saving trace ({1}) in {2}...", operation, category, fileName); var serializableOperation = new SerializableOperation(operation); var stopwatchExecutionProperty = GetStopwatchExecutionPropertyKey(category); if (operation.ExecutionProperties.ContainsKey(stopwatchExecutionProperty)) { var stopwatch = (Stopwatch) operation.ExecutionProperties[stopwatchExecutionProperty]; stopwatch.Stop(); serializableOperation.ElapsedMilliseconds = stopwatch.ElapsedMilliseconds; } using (var writeStream = File.OpenWrite(fileName)) { serializableOperation.Serialize(writeStream); } if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: successfully traced ({1}) in {1}.", operation, category, fileName); }
protected virtual void ReadEncoding(IRemoraOperation operation, HttpWebResponse response, IComponentDefinition componentDefinition) { if (Logger.IsDebugEnabled) Logger.DebugFormat("Determining encoding for response from {0} for operation {1}...", response.ResponseUri, operation); if ((operation.ExecutingPipeline != null) && (operation.ExecutingPipeline.Definition != null) && (operation.ExecutingPipeline.Definition.Properties.ContainsKey("forceResponseEncoding")) ) { try { operation.Response.ContentEncoding = Encoding.GetEncoding(operation.ExecutingPipeline.Definition.Properties["forceResponseEncoding"]); if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: encoding forced to {1}.", operation, operation.Response.ContentEncoding); } catch (ArgumentException ex) { Logger.ErrorFormat(ex, "There has been an error while loading encoding defined in forceResponseEncoding property: {0}", operation.ExecutingPipeline.Definition.Properties["forceResponseEncoding"]); throw; } } else { var encoding = Encoding.UTF8; // default; if (!string.IsNullOrEmpty(response.CharacterSet)) { try { encoding = Encoding.GetEncoding(response.CharacterSet); if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: loaded encoding {1} from character set: {2}", operation, encoding.EncodingName, response.CharacterSet); } catch (ArgumentException ex) { Logger.WarnFormat(ex, "Operation {0}: unable to load a proper encoding for character set {1}", operation, response.CharacterSet); } } else { if (Logger.IsDebugEnabled) Logger.DebugFormat("Operation {0}: using default encoding {0}", operation, encoding.EncodingName); } operation.Response.ContentEncoding = encoding; } }