UNPKG

@jaricardodev/ews-javascript-api

Version:
465 lines (396 loc) 17.2 kB
import { AutodiscoverErrorCode } from "../../Enumerations/AutodiscoverErrorCode"; import { AutodiscoverResponse } from "../Responses/AutodiscoverResponse"; import { AutodiscoverResponseException } from "../../Exceptions/AutodiscoverResponseException"; import { AutodiscoverService } from "../AutodiscoverService"; import { EwsLogging } from "../../Core/EwsLogging"; import { EwsServiceXmlWriter } from "../../Core/EwsServiceXmlWriter"; import { EwsUtilities } from "../../Core/EwsUtilities"; import { EwsXmlReader } from "../../Core/EwsXmlReader"; import { ExchangeServerInfo } from "../../Core/ExchangeServerInfo"; import { ExchangeVersion } from "../../Enumerations/ExchangeVersion"; import { IXHROptions } from "../../Interfaces"; import { ServiceResponse } from "../../Core/Responses/ServiceResponse"; import { ServiceResponseException } from "../../Exceptions/ServiceResponseException"; import { SoapFaultDetails } from "../../Misc/SoapFaultDetails"; import { Uri } from "../../Uri"; import { XmlElementNames } from "../../Core/XmlElementNames"; import { XmlNamespace } from "../../Enumerations/XmlNamespace"; import { HttpStatusCode } from "../../../lib/HttpStatusCode"; /** * @internal Represents the base class for all requested made to the Autodiscover service. */ export abstract class AutodiscoverRequest { private service: AutodiscoverService; private url: Uri = null; /** * @internal Gets the URL. */ get Service(): AutodiscoverService { return this.service; } /** * @internal Gets the service. */ get Url(): Uri { return this.url; } /** * @internal Initializes a new instance of the **AutodiscoverRequest** class. * * @param {AutodiscoverService} service Autodiscover service associated with this request. * @param {Uri} url URL of Autodiscover service. */ constructor(service: AutodiscoverService, url: Uri) { this.service = service; this.url = url; } private CreateRedirectionResponse(httpWebResponse: any /*IEwsHttpWebResponse*/): AutodiscoverResponse { //string location = httpWebResponse.Headers[System.Net.HttpResponseHeader.Location]; // if (!string.IsNullOrEmpty(location)) { // try { // Uri redirectionUri = new Uri(this.Url, location); // if ((redirectionUri.Scheme == Uri.UriSchemeHttp) || (redirectionUri.Scheme == Uri.UriSchemeHttps)) { // AutodiscoverResponse response = this.CreateServiceResponse(); // response.ErrorCode = AutodiscoverErrorCode.RedirectUrl; // response.RedirectionUrl = redirectionUri; // return response; // } // this.Service.TraceMessage( // TraceFlags.AutodiscoverConfiguration, // string.Format("Invalid redirection URL '{0}' returned by Autodiscover service.", redirectionUri)); // } // catch (UriFormatException) { // this.Service.TraceMessage( // TraceFlags.AutodiscoverConfiguration, // string.Format("Invalid redirection location '{0}' returned by Autodiscover service.", location)); // } // } // else { // this.Service.TraceMessage( // TraceFlags.AutodiscoverConfiguration, // "Redirection response returned by Autodiscover service without redirection location."); // } return null; } /** * @internal Creates the service response. * * @return {AutodiscoverResponse} AutodiscoverResponse */ abstract CreateServiceResponse(): AutodiscoverResponse; /** * Gets the name of the request XML element. * * @return {string} [description] */ abstract GetRequestXmlElementName(): string; GetResponseStream(response: any /*IEwsHttpWebResponse*/): any { //System.IO.Stream{ //string contentEncoding = response.ContentEncoding; //Stream responseStream = response.GetResponseStream(); //if (contentEncoding.ToLowerInvariant().Contains("gzip")) { // return new GZipStream(responseStream, CompressionMode.Decompress); //} //else if (contentEncoding.ToLowerInvariant().Contains("deflate")) { // return new DeflateStream(responseStream, CompressionMode.Decompress); //} //else { // return responseStream; //} } /** * @internal Gets the name of the response XML element. * * @return {string} [description] */ abstract GetResponseXmlElementName(): string; /** * @internal Gets the WS-Addressing action name. * * @return {string} [description] */ abstract GetWsAddressingActionName(): string; /** * Executes this instance. * * @return {Promise<AutodiscoverResponse>} [description] */ async InternalExecute(): Promise<AutodiscoverResponse> { this.Validate(); try { var writer = new EwsServiceXmlWriter(this.service); this.WriteSoapRequest(this.url, writer); if (!this.service) throw new Error("Missing Service"); var cc = writer.GetXML(); var xhrOptions: IXHROptions = { type: "POST", data: cc, url: this.url.ToString(), headers: { "Content-Type": "text/xml" }, }; //If not set, credentials might come from custom XHRApi if (this.service.Credentials) { this.service.Credentials.PrepareWebRequest(xhrOptions); } EwsLogging.DebugLog("sending ews request"); EwsLogging.DebugLog({ ...xhrOptions, ...{ headers: { ...xhrOptions.headers, Authorization: "REDACTED" } }}, true); const xhrResponse = await this.service.XHRApi.xhr(xhrOptions) const ewsXmlReader = new EwsXmlReader(xhrResponse.responseText || xhrResponse.response); const responseObject = ewsXmlReader.JsObject; EwsLogging.DebugLog(responseObject, true); if (xhrResponse.status == 200) { EwsLogging.DebugLog(xhrResponse, true); this.ReadSoapHeader(responseObject[XmlElementNames.SOAPHeaderElementName]); var response: AutodiscoverResponse = this.ReadSoapBody(responseObject); if (response.ErrorCode == AutodiscoverErrorCode.NoError) { //todo: passon to successDelegate //return response; } else { throw new AutodiscoverResponseException(response.ErrorCode, response.ErrorMessage); } } else { EwsLogging.Log("status !== 200", true, true); EwsLogging.Log(xhrResponse.response, true, true); EwsLogging.Log(ewsXmlReader, true, true); } return response || xhrResponse.responseText || xhrResponse.response; } catch (resperr) { let exception: any; try { this.ProcessWebException(resperr); } catch (exc) { exception = exc; } throw (exception || resperr.responseText || resperr.response); } } /** * @internal Determines whether response is a redirection. * * @param {XMLHttpRequest} httpWebResponse The HTTP web response. * @return {boolean} True if redirection response. */ static IsRedirectionResponse(httpWebResponse: XMLHttpRequest): boolean { return (httpWebResponse.status == HttpStatusCode.Redirect) || (httpWebResponse.status == HttpStatusCode.Moved) || (httpWebResponse.status == HttpStatusCode.RedirectKeepVerb) || (httpWebResponse.status == HttpStatusCode.RedirectMethod); } /** * @internal Loads response from XML. * * @param {any} responseObject Json Object converted from XML. */ LoadFromXmlJsObject(jsObject: any): AutodiscoverResponse { const elementName = this.GetResponseXmlElementName(); const responseObject = jsObject[elementName]; var response = this.CreateServiceResponse(); response.LoadFromXmlJsObject(responseObject[XmlElementNames.Response]); return response; } /** * Processes the web exception. * * @param {XMLHttpRequest} webException The web exception. */ private ProcessWebException(webException: XMLHttpRequest): void { if (webException.response) { //IEwsHttpWebResponse httpWebResponse = this.Service.HttpWebRequestFactory.CreateExceptionResponse(webException); var soapFaultDetails: SoapFaultDetails = null; if (webException.status == HttpStatusCode.InternalServerError) { // If tracing is enabled, we read the entire response into a MemoryStream so that we // can pass it along to the ITraceListener. Then we parse the response from the // MemoryStream. //if (this.Service.IsTraceEnabledFor(TraceFlags.AutodiscoverRequest)) { //using(MemoryStream memoryStream = new MemoryStream()) //{ // using(Stream serviceResponseStream = AutodiscoverRequest.GetResponseStream(httpWebResponse)) // { // // Copy response to in-memory stream and reset position to start. // EwsUtilities.CopyStream(serviceResponseStream, memoryStream); // memoryStream.Position = 0; // } //todo implement tracing to base class. //this.Service.TraceResponse(httpWebResponse, memoryStream); //var reader = new EwsXmlReader(webException.responseText); //soapFaultDetails = this.ReadSoapFault(reader); //} //} //else { // using(Stream stream = AutodiscoverRequest.GetResponseStream(httpWebResponse)) // { // EwsXmlReader reader = new EwsXmlReader(stream); // soapFaultDetails = this.ReadSoapFault(reader); // } //} var reader = new EwsXmlReader(webException.responseText || webException.response); soapFaultDetails = this.ReadSoapFault(reader.JsObject); if (soapFaultDetails) { //todo: implement soap fault error throw throw new ServiceResponseException(new ServiceResponse(soapFaultDetails)); } } else { //todo: fix this this.Service.ProcessHttpErrorResponse(webException, webException); } } } /** * @internal Read SOAP body. * * @param {object} jsObject EwsXmlReader * @returns {AutodiscoverResponse} AutodiscoverResponse */ ReadSoapBody(jsObject: object): AutodiscoverResponse { var responses = this.LoadFromXmlJsObject(jsObject[XmlElementNames.SOAPBodyElementName]); return responses } /** * Reads the SOAP fault. * * @param {any} jsObject The reader. * @return {SoapFaultDetails} SOAP fault details. */ private ReadSoapFault(jsObject: any): SoapFaultDetails { var soapFaultDetails: SoapFaultDetails = undefined; if (jsObject && jsObject[XmlElementNames.SOAPBodyElementName]) { var obj = jsObject[XmlElementNames.SOAPBodyElementName]; if (obj[XmlElementNames.SOAPFaultElementName]) soapFaultDetails = SoapFaultDetails.Parse(obj[XmlElementNames.SOAPFaultElementName]); } return soapFaultDetails; //skipped xml section, using Json only. //////try { ////// // WCF may not generate an XML declaration. ////// reader.Read(); ////// //if (reader.NodeType == Node. System.Xml.XmlNodeType.XmlDeclaration) { ////// // reader.Read(); ////// //} ////// if (reader.LocalName != XmlElementNames.SOAPEnvelopeElementName) { ////// return soapFaultDetails; ////// } ////// // Get the namespace URI from the envelope element and use it for the rest of the parsing. ////// // If it's not 1.1 or 1.2, we can't continue. ////// var soapNamespace: XmlNamespace = EwsUtilities.GetNamespaceFromUri(reader.NamespaceUri); ////// if (soapNamespace == XmlNamespace.NotSpecified) { ////// return soapFaultDetails; ////// } ////// reader.Read(); ////// // Skip SOAP header. ////// if (reader.IsElement(soapNamespace, XmlElementNames.SOAPHeaderElementName)) { ////// do { ////// reader.Read(); ////// } ////// while (reader.HasRecursiveParent(XmlElementNames.SOAPHeaderElementName)); ////// // Queue up the next read ////// //reader.Read(); - no need with nodeiterator/treewalker as the node is already a body Node ////// } ////// // Parse the fault element contained within the SOAP body. ////// if (reader.IsElement(soapNamespace, XmlElementNames.SOAPBodyElementName)) { ////// do { ////// reader.Read(); ////// // Parse Fault element ////// if (reader.IsElement(soapNamespace, XmlElementNames.SOAPFaultElementName)) { ////// soapFaultDetails = SoapFaultDetails.Parse(reader, soapNamespace); ////// } ////// } ////// while (reader.HasRecursiveParent(XmlElementNames.SOAPBodyElementName)); ////// } //////} //////catch (XmlException) { ////// // If response doesn't contain a valid SOAP fault, just ignore exception and ////// // return null for SOAP fault details. //////} //////return soapFaultDetails; } /** * @internal Read SOAP headers. * * @param {object} reader EwsXmlReader */ ReadSoapHeader(jsobject: object): void { this.service.ServerInfo = ExchangeServerInfo.Parse(jsobject[XmlElementNames.ServerVersionInfo]); } /** * @internal Validates the request. */ Validate(): void { this.Service.Validate(); } /** * @internal Writes attributes to request XML. * * @param {EwsServiceXmlWriter} writer The writer. */ abstract WriteAttributesToXml(writer: EwsServiceXmlWriter): void; /** * @internal Writes XML body. * * @param {EwsServiceXmlWriter} writer The writer. */ WriteBodyToXml(writer: EwsServiceXmlWriter): void { writer.WriteStartElement(XmlNamespace.Autodiscover, this.GetRequestXmlElementName()); this.WriteAttributesToXml(writer); this.WriteElementsToXml(writer); writer.WriteEndElement(); // m:this.GetXmlElementName() } /** * @internal Writes elements to request XML. * * @param {EwsServiceXmlWriter} writer The writer. */ abstract WriteElementsToXml(writer: EwsServiceXmlWriter): void; /** * @internal Write extra headers. * * @param {EwsServiceXmlWriter} writer The writer */ WriteExtraCustomSoapHeadersToXml(writer: EwsServiceXmlWriter): void { } /** * @internal Writes the autodiscover SOAP request. * * @param {Uri} requestUrl Request URL. * @param {EwsServiceXmlWriter} writer The writer. */ WriteSoapRequest(requestUrl: Uri, writer: EwsServiceXmlWriter): void { writer.WriteStartElement(XmlNamespace.Soap, XmlElementNames.SOAPEnvelopeElementName); writer.WriteAttributeValue("xmlns", EwsUtilities.AutodiscoverSoapNamespacePrefix, EwsUtilities.AutodiscoverSoapNamespace); writer.WriteAttributeValue("xmlns", EwsUtilities.WSAddressingNamespacePrefix, EwsUtilities.WSAddressingNamespace); writer.WriteAttributeValue("xmlns", EwsUtilities.EwsXmlSchemaInstanceNamespacePrefix, EwsUtilities.EwsXmlSchemaInstanceNamespace); if (writer.RequireWSSecurityUtilityNamespace) { writer.WriteAttributeValue("xmlns", EwsUtilities.WSSecurityUtilityNamespacePrefix, EwsUtilities.WSSecurityUtilityNamespace); } writer.WriteStartElement(XmlNamespace.Soap, XmlElementNames.SOAPHeaderElementName); if (this.Service.Credentials != null) { this.Service.Credentials.EmitExtraSoapHeaderNamespaceAliases(writer); } writer.WriteElementValue( XmlNamespace.Autodiscover, XmlElementNames.RequestedServerVersion, ExchangeVersion[this.Service.RequestedServerVersion] ); writer.WriteElementValue( XmlNamespace.WSAddressing, XmlElementNames.Action, this.GetWsAddressingActionName()); writer.WriteElementValue( XmlNamespace.WSAddressing, XmlElementNames.To, requestUrl.AbsoluteUri); this.WriteExtraCustomSoapHeadersToXml(writer); //if (this.Service.Credentials != null) { // this.Service.Credentials.SerializeWSSecurityHeaders(writer.InternalWriter); //} //this.Service.DoOnSerializeCustomSoapHeaders(writer.InternalWriter); writer.WriteEndElement(); // soap:Header writer.WriteStartElement(XmlNamespace.Soap, XmlElementNames.SOAPBodyElementName); this.WriteBodyToXml(writer); writer.WriteEndElement(); // soap:Body writer.WriteEndElement(); // soap:Envelope writer.Flush(); } }