/// <summary> /// A method used to get the HTTP method value according to the WOPI operation name. /// </summary> /// <param name="operationName">A parameter represents the WOPI operation name.</param> /// <returns>A return value represents the HTTP method value for the WOPI operation.</returns> private string GetHttpMethodForWOPIOperation(WOPIOperationName operationName) { string httpMethod = string.Empty; switch (operationName) { case WOPIOperationName.CheckFileInfo: case WOPIOperationName.CheckFolderInfo: case WOPIOperationName.GetFile: case WOPIOperationName.EnumerateChildren: { httpMethod = WebRequestMethods.Http.Get; break; } default: { httpMethod = WebRequestMethods.Http.Post; break; } } return(httpMethod); }
/// <summary> /// A method is used to get the X-WOPI-Override header value according to the operation name. /// </summary> /// <param name="operationName">A parameter represents the operation name.</param> /// <returns>A return value represents the X-WOPI-Override header value which is used by specified operation.</returns> private string GetTheXWOPIOverrideHeaderValue(WOPIOperationName operationName) { string valueTemp = string.Empty; switch (operationName) { case WOPIOperationName.Lock: case WOPIOperationName.UnlockAndRelock: { valueTemp = "LOCK"; break; } case WOPIOperationName.PutFile: { valueTemp = "PUT"; break; } case WOPIOperationName.UnLock: { valueTemp = "UNLOCK"; break; } case WOPIOperationName.PutRelativeFile: { valueTemp = "PUT_RELATIVE"; break; } case WOPIOperationName.RefreshLock: { valueTemp = "REFRESH_LOCK"; break; } case WOPIOperationName.ExecuteCellStorageRequest: case WOPIOperationName.ExecuteCellStorageRelativeRequest: { valueTemp = "COBALT"; break; } case WOPIOperationName.DeleteFile: { valueTemp = "DELETE"; break; } case WOPIOperationName.GetRestrictedLink: { valueTemp = "GET_RESTRICTED_LINK"; break; } case WOPIOperationName.RevokeRestrictedLink: { valueTemp = "REVOKE_RESTRICTED_LINK"; break; } case WOPIOperationName.ReadSecureStore: { valueTemp = "READ_SECURE_STORE"; break; } default: { string errorMsg = string.Format(@"There is no valid [X-WOPI-Override] header value for operation[{0}]", operationName); throw new InvalidOperationException(errorMsg); } } return(valueTemp); }
/// <summary> /// A method used to log the HTTP transport information. /// </summary> /// <param name="wopiRequest">A parameter represents the request instance of a WOPI operation. It must not be null.</param> /// <param name="requestBody">A parameter represents the request body of a WOPI operation.</param> /// <param name="wopiResponse">A parameter represents the response of a WOPI operation. It must not be null if the "isResponse" parameter is true.</param> /// <param name="operationName">A parameter represents the WOPI operation name.</param> /// <param name="isResponse">A parameter represents the HTTP transport information recorded by this method whether belong to the response of a WOPI operation.</param> private void LogHttpTransportInfo(HttpWebRequest wopiRequest, byte[] requestBody, WOPIHttpResponse wopiResponse, WOPIOperationName operationName, bool isResponse = true) { #region validate parameters if (isResponse) { if (null == wopiResponse) { throw new ArgumentNullException("wopiResponse"); } // For log response, requires the request URL. if (null == wopiRequest) { throw new ArgumentNullException("wopiRequest"); } } else { if (null == wopiRequest) { throw new ArgumentNullException("wopiRequest"); } } #endregion #region headers // Build headers information StringBuilder headerInfoBuilder = new StringBuilder(); WebHeaderCollection headers = isResponse ? wopiResponse.Headers : wopiRequest.Headers; if (null != headers && 0 != headers.Count) { foreach (string oheaderNameItem in headers.AllKeys) { string headerValueString = string.Format( "[{0}]:({1})", oheaderNameItem, headers[oheaderNameItem]); headerInfoBuilder.AppendLine(headerValueString); } } #endregion #region body information // Build body information byte[] httpBodyOfResponse = null; if (isResponse && 0 != wopiResponse.ContentLength) { httpBodyOfResponse = WOPIResponseHelper.GetContentFromResponse(wopiResponse); } byte[] httpBody = isResponse ? httpBodyOfResponse : requestBody; StringBuilder bodyInfoBuilder = new StringBuilder(); if (null != httpBody && 0 != httpBody.Length) { switch (operationName) { case WOPIOperationName.CheckFileInfo: case WOPIOperationName.ReadSecureStore: case WOPIOperationName.CheckFolderInfo: case WOPIOperationName.EnumerateChildren: { if (isResponse) { // log response body by JSON format bodyInfoBuilder.AppendLine(Encoding.UTF8.GetString(httpBody)); } break; } case WOPIOperationName.PutRelativeFile: { if (isResponse) { // log the body by JSON format bodyInfoBuilder.AppendLine(Encoding.UTF8.GetString(httpBody)); } else { // log the body as bytes string value bodyInfoBuilder.AppendLine(WOPIResponseHelper.GetBytesStringValue(httpBody)); } break; } case WOPIOperationName.GetFile: { if (isResponse) { // log the body as bytes string value bodyInfoBuilder.AppendLine(WOPIResponseHelper.GetBytesStringValue(httpBody)); } break; } case WOPIOperationName.PutFile: { if (!isResponse) { // log the body as bytes string value bodyInfoBuilder.AppendLine(WOPIResponseHelper.GetBytesStringValue(httpBody)); } break; } } } #endregion string credentialInfo = string.Format( "User:[{0}] Domain:[{1}]", this.defaultUserName, this.defaultDomain); string logTitle = string.Format( "{0} HTTP {1}{2} for [{3}] operation:", isResponse ? "Receive" : "Sending", isResponse ? "Response" : "Request", isResponse ? string.Empty : " with " + credentialInfo, operationName); StringBuilder logBuilder = new StringBuilder(); logBuilder.AppendLine(logTitle); string urlInfor = string.Format("Request URL:[{0}]", wopiRequest.RequestUri.AbsoluteUri); logBuilder.AppendLine(urlInfor); string httpMethodValue = string.Format("HTTP method:[{0}]", this.GetHttpMethodForWOPIOperation(operationName)); logBuilder.AppendLine(httpMethodValue); if (isResponse) { string httpStatusCodeValue = string.Format("HTTP status code:[{0}]", wopiResponse.StatusCode); logBuilder.AppendLine(httpStatusCodeValue); } string headerInfo = string.Format("Headers:\r\n{0}", 0 == headerInfoBuilder.Length ? "None" : headerInfoBuilder.ToString()); logBuilder.AppendLine(headerInfo); string bodyInfo = string.Format("Body:\r\n{0}", 0 == bodyInfoBuilder.Length ? "None" : bodyInfoBuilder.ToString()); logBuilder.AppendLine(bodyInfo); this.Site.Log.Add(LogEntryKind.Debug, logBuilder.ToString()); }
/// <summary> /// A method is used to record information about web exception which is thrown by calling protocol operations. /// </summary> /// <param name="targetResourceUrl">A parameter represents the request URL which cause a web exception.</param> /// <param name="wopiOperationName">A parameter represents the protocol operation name which sends a http request and then get a web exception.</param> /// <param name="webException">A parameter represents web exception instance.</param> protected virtual void RecordWebExceptionInformation(string targetResourceUrl, WOPIOperationName wopiOperationName, WebException webException) { string errorHeaderValue = this.GetWebExceptionHeadersValue(webException); if (!string.IsNullOrEmpty(errorHeaderValue)) { this.Site.Log.Add( LogEntryKind.Debug, "Perform the [{0}] operation fail. Request URL:[{1}]\r\nError headers:\r\n{2}", wopiOperationName, targetResourceUrl, errorHeaderValue); } }
/// <summary> /// A method is used to send http request for MS-WOPI operation. /// </summary> /// <param name="targetResourceUrl">A parameter represents the target resource Uri.</param> /// <param name="headers">A parameter represents the headers which is included in the http request.</param> /// <param name="body">A parameter represents the body contents which is sent in the http request.</param> /// <param name="operationName">A parameter represents the WOPI operation which the http request belongs to.</param> /// <returns>A return value represents the http response of the http request which is sent with specified header, URI, body and http method. </returns> protected virtual WOPIHttpResponse SendWOPIRequest(string targetResourceUrl, WebHeaderCollection headers, byte[] body, WOPIOperationName operationName) { HttpWebResponse responseTemp = null; HttpWebRequest request = null; request = (HttpWebRequest)HttpWebRequest.Create(targetResourceUrl); request.Method = this.GetHttpMethodForWOPIOperation(operationName); // Setting the required common headers if (null == headers) { headers = new WebHeaderCollection(); } request.Headers = headers; if (null == body || 0 == body.Length) { request.ContentLength = 0; } else { request.ContentLength = body.Length; request.ContentType = "application/binary"; Stream stream = request.GetRequestStream(); stream.Write(body, 0, body.Length); } // Get the response by default user credential request.Credentials = new NetworkCredential(this.defaultUserName, this.defaultPassword, this.defaultDomain); // Log the HTTP request this.LogHttpTransportInfo(request, body, null, operationName, false); try { responseTemp = request.GetResponse() as HttpWebResponse; } catch (WebException webEx) { this.Site.Log.Add( LogEntryKind.Debug, @"There is a WebException generated when sending WOPI request. Exception message[{0}],\r\nStackTrace:[{1}]", webEx.Message, webEx.StackTrace); this.RecordWebExceptionInformation(targetResourceUrl, operationName, webEx); throw; } WOPIHttpResponse wopiHttpResponse = new WOPIHttpResponse(responseTemp); // Log the HTTP response this.LogHttpTransportInfo(request, null, wopiHttpResponse, operationName); this.ValidateCommonMessageCapture(); return(wopiHttpResponse); }
/// <summary> /// A method used to get the HTTP method value according to the WOPI operation name. /// </summary> /// <param name="operationName">A parameter represents the WOPI operation name.</param> /// <returns>A return value represents the HTTP method value for the WOPI operation.</returns> private string GetHttpMethodForWOPIOperation(WOPIOperationName operationName) { string httpMethod = string.Empty; switch (operationName) { case WOPIOperationName.CheckFileInfo: case WOPIOperationName.CheckFolderInfo: case WOPIOperationName.GetFile: case WOPIOperationName.EnumerateChildren: { httpMethod = WebRequestMethods.Http.Get; break; } default: { httpMethod = WebRequestMethods.Http.Post; break; } } return httpMethod; }
/// <summary> /// A method is used to get the X-WOPI-Override header value according to the operation name. /// </summary> /// <param name="operationName">A parameter represents the operation name.</param> /// <returns>A return value represents the X-WOPI-Override header value which is used by specified operation.</returns> private string GetTheXWOPIOverrideHeaderValue(WOPIOperationName operationName) { string valueTemp = string.Empty; switch (operationName) { case WOPIOperationName.Lock: case WOPIOperationName.UnlockAndRelock: { valueTemp = "LOCK"; break; } case WOPIOperationName.PutFile: { valueTemp = "PUT"; break; } case WOPIOperationName.UnLock: { valueTemp = "UNLOCK"; break; } case WOPIOperationName.PutRelativeFile: { valueTemp = "PUT_RELATIVE"; break; } case WOPIOperationName.RefreshLock: { valueTemp = "REFRESH_LOCK"; break; } case WOPIOperationName.ExecuteCellStorageRequest: case WOPIOperationName.ExecuteCellStorageRelativeRequest: { valueTemp = "COBALT"; break; } case WOPIOperationName.DeleteFile: { valueTemp = "DELETE"; break; } case WOPIOperationName.GetRestrictedLink: { valueTemp = "GET_RESTRICTED_LINK"; break; } case WOPIOperationName.RevokeRestrictedLink: { valueTemp = "REVOKE_RESTRICTED_LINK"; break; } case WOPIOperationName.ReadSecureStore: { valueTemp = "READ_SECURE_STORE"; break; } default: { string errorMsg = string.Format(@"There is no valid [X-WOPI-Override] header value for operation[{0}]", operationName); throw new InvalidOperationException(errorMsg); } } return valueTemp; }
/// <summary> /// A method is used to send http request for MS-WOPI operation. /// </summary> /// <param name="targetResourceUrl">A parameter represents the target resource Uri.</param> /// <param name="headers">A parameter represents the headers which is included in the http request.</param> /// <param name="body">A parameter represents the body contents which is sent in the http request.</param> /// <param name="operationName">A parameter represents the WOPI operation which the http request belongs to.</param> /// <returns>A return value represents the http response of the http request which is sent with specified header, URI, body and http method. </returns> protected virtual WOPIHttpResponse SendWOPIRequest(string targetResourceUrl, WebHeaderCollection headers, byte[] body, WOPIOperationName operationName) { HttpWebResponse responseTemp = null; HttpWebRequest request = null; request = (HttpWebRequest)HttpWebRequest.Create(targetResourceUrl); request.Method = this.GetHttpMethodForWOPIOperation(operationName); // Setting the required common headers if (null == headers) { headers = new WebHeaderCollection(); } request.Headers = headers; if (null == body || 0 == body.Length) { request.ContentLength = 0; } else { request.ContentLength = body.Length; request.ContentType = "application/binary"; Stream stream = request.GetRequestStream(); stream.Write(body, 0, body.Length); } // Get the response by default user credential request.Credentials = new NetworkCredential(this.defaultUserName, this.defaultPassword, this.defaultDomain); // Log the HTTP request this.LogHttpTransportInfo(request, body, null, operationName, false); try { responseTemp = request.GetResponse() as HttpWebResponse; } catch (WebException webEx) { this.Site.Log.Add( LogEntryKind.Debug, @"There is a WebException generated when sending WOPI request. Exception message[{0}],\r\nStackTrace:[{1}]", webEx.Message, webEx.StackTrace); this.RecordWebExceptionInformation(targetResourceUrl, operationName, webEx); throw; } WOPIHttpResponse wopiHttpResponse = new WOPIHttpResponse(responseTemp); // Log the HTTP response this.LogHttpTransportInfo(request, null, wopiHttpResponse, operationName); this.ValidateCommonMessageCapture(); return wopiHttpResponse; }