/// <summary> /// The method is used to send PCCRTP response message. /// </summary> /// <param name="response">The PCCRTP response message.</param> public void SentPccrtpResponse(PccrtpResponse response) { this.httpServerTransport.Send( response.HttpHeader, response.PayloadData, this.httpListenerContext); this.httpListenerContext = null; }
/// <summary> /// Verify requirements about content information structure. /// </summary> /// <param name="pccrtpResponse">The PCCRTP response message.</param> private void VerifyContentInfomationStructure(PccrtpResponse pccrtpResponse) { Site.DefaultProtocolDocShortName = "MS-PCCRC"; this.VerifyContentSegmentsBlocks(pccrtpResponse); this.VerifySegmentIdentifiersAndKeys(pccrtpResponse); this.VerifyDataStructure(pccrtpResponse); this.VerifySegmentDescription(pccrtpResponse); this.VerifySegmentContentBlocks(pccrtpResponse); Site.DefaultProtocolDocShortName = "MS-PCCRTP"; }
/// <summary> /// Generate PCCRTP response message to reply the client request. /// </summary> /// <param name="resourceLocator">The client request URI.</param> /// <param name="serverSecret">The server secret set on the server endpoint.</param> /// <returns>Returns the PCCRTP response message.</returns> public PccrtpResponse GenerateResponseMessage(string resourceLocator, string serverSecret) { PccrtpResponse pccrtpResponse = new PccrtpResponse(); Dictionary <string, string> tempHttpHeader = new Dictionary <string, string>(); HashGeneration hashHelp = new HashGeneration(serverSecret, dwHashAlgo_Values.SHA256); byte[] fileData = PccrcUtility.ReadFile(resourceLocator); Content_Information_Data_Structure contentInfo = hashHelp.GenerateContentInformation(fileData); tempHttpHeader.Add(CONTENTENCODING, "peerdist"); tempHttpHeader.Add(XP2PPEERDIST, "Version=1.0, ContentLength=" + fileData.Length); pccrtpResponse.HttpHeader = tempHttpHeader; pccrtpResponse.PayloadData = contentInfo.ToByteArray(); return(pccrtpResponse); }
/// <summary> /// Get the pccrtp response with http header "peerdist". /// </summary> /// <param name="serverAddress"> The content server address.</param> /// <param name="port"> The port that the content server is listening.</param> /// <param name="uri"> The path of the file to request.</param> /// <returns>Only true can be returned that specifies the pccrtp response with /// http header "peerdist" is received.</returns> /// <exception cref="Exception">No http response with "peerdist" header is received,</exception> private bool GetPccrtpResponse(string serverAddress, int port, string uri) { PccrtpRequest pccrtpRequest = this.pccrtpStackClient.CreatePccrtpRequest(serverAddress, port, uri); PccrtpResponse pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000); int timesOfSendingPccrtpMsg = 1; while (!pccrtpResponseTemp.HttpResponse.ContentEncoding.Equals("peerdist")) { if (timesOfSendingPccrtpMsg >= 3) { throw new InvalidOperationException(string.Format( "Send {0} times Pccrtp request message, no http response with \"peerdist\" header is received.", timesOfSendingPccrtpMsg)); } pccrtpResponseTemp = this.pccrtpStackClient.SendHttpRequest( Microsoft.Protocols.TestTools.StackSdk.BranchCache.Pccrtp.HttpVersionType.HttpVersion11, pccrtpRequest, int.Parse(Site.Properties["PCCRTP.Protocol.TimeOut"]) * 1000); timesOfSendingPccrtpMsg++; } this.pccrtpResponse = pccrtpResponseTemp; return true; }
/// <summary> /// Reset the adapter /// </summary> public override void Reset() { base.Reset(); this.isReceived = false; this.pccrtpResponse = null; if (this.pccrrServer != null) { this.pccrrServer.CloseConnections(); this.pccrrServer = null; } }
/// <summary> /// This class is used to verify the requirements related to PCCRTP response. /// </summary> /// <param name="pccrtpResponse">The PCCRTP response message.</param> private void VerifyPccrtpResponse(PccrtpResponse pccrtpResponse) { #region MS-PCCRTP_R11 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R11. Actual value of X-P2P-PeerDist field is: {0}.", pccrtpResponse.HttpHeader[XP2PPEERDIST]); bool isVerifyR11 = pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("Version") && pccrtpResponse.HttpResponse.Headers[XP2PPEERDIST].Contains("ContentLength"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R11 Site.CaptureRequirementIfIsTrue( isVerifyR11, 11, @"[In Message Syntax] The extension-header field can appear in responses, the syntax of this header field value is described as follows: extension-header = X-P2P-PeerDist X-P2P-PeerDist = ""X-P2P-PeerDist"" "":"" peerdist-params [peerdist-params = 1#( version | [content-len] | [missing-data-request] ) version = ""Version"" ""="" major-version ""."" minor-version]. "); #endregion #region MS-PCCRTP_R18 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R18. Actual Value of Content-Length is {0}", pccrtpResponse.HttpHeader[CONTENTLENGTH]); long contentLength; // Verify MS-PCCRTP requirement: MS-PCCRTP_R18 bool isVerifyR18 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader[CONTENTLENGTH]) && long.TryParse(pccrtpResponse.HttpHeader[CONTENTLENGTH], out contentLength); Site.CaptureRequirementIfIsTrue( isVerifyR18, 18, @"[In Message Syntax] The content-len [content-len = ""ContentLength"" ""="" 1*DIGIT] parameter contains the length of the entity-body before the PeerDist content encoding is applied to it."); #endregion #region MS-PCCRTP_R34 bool isVerifyR34 = pccrtpResponse.HttpHeader.Values.Contains(pccrtpResponse.HttpHeader["X-P2P-PeerDist"]); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R34. The response {0} contain PeerDist parameters header field.", isVerifyR34 ? string.Empty : "does not "); // Verify MS-PCCRTP requirement: MS-PCCRTP_R34 Site.CaptureRequirementIfIsTrue( isVerifyR34, 34, @"[In Receiving a PeerDist-Supporting Request] HTTP/1.1 server MUST also include the PeerDist parameters header field in the response."); #endregion #region MS-PCCRTP_R35 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R35. Actual Value of Version is {0}", pccrtpResponse.HttpHeader[XP2PPEERDIST]); // Verify MS-PCCRTP requirement: MS-PCCRTP_R35 bool isVerifyR35 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("Version"); Site.CaptureRequirementIfIsTrue( isVerifyR35, 35, @"[In Receiving a PeerDist-Supporting Request] The PeerDist parameters header field MUST contain the Version parameter containing the version of the PeerDist content encoding used in the response."); #endregion #region MS-PCCRTP_R36 bool isVerifyR36 = pccrtpResponse.HttpHeader[XP2PPEERDIST].Contains("ContentLength"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R36. Actual Value of ContentLength is {0} in PeerDist Header field", isVerifyR36 ? string.Empty : "not"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R36 Site.CaptureRequirementIfIsTrue( isVerifyR36, 36, @"[In Receiving a PeerDist-Supporting Request] the PeerDist parameters header field MUST also contain the ContentLength parameter specifying the content length of the response entity-body before the PeerDist content encoding has been applied to it."); #endregion #region MS-PCCRTP_R48 string[] headerValues = pccrtpResponse.HttpHeader[XP2PPEERDIST].Split(new char[] { ',' }); string versionString = headerValues[0].Substring(headerValues[0].IndexOf('=') + 1); // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRTP_R48. Actual Value of peerdist version is {0}", versionString); if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { // Verify MS-PCCRTP requirement: MS-PCCRTP_R48 Site.CaptureRequirementIfAreEqual<string>( "1.0", versionString, 48, @"[In Appendix A: Product Behavior]<3> Section 1.7: HTTP/1.1 servers in Windows Server 2008 R2 set the PeerDist version parameter to 1.0."); } #endregion #region MS-PCCRTP_R52 if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { bool isContainEtag = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag"); bool isContainLastModified = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified"); bool isContainBoth = pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("ETag") && pccrtpResponse.HttpResponse.Headers.AllKeys.Contains("Last-Modified"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R52.The response actually does {0} contain an ETag header field, does {1} contain a Last-Modified header field, does {2} contain both header fields.", isContainEtag ? string.Empty : "not", isContainLastModified ? string.Empty : "not", isContainBoth ? string.Empty : "not"); bool isVerifyR52 = isContainEtag || isContainLastModified || isContainBoth; // Verify MS-PCCRTP requirement: MS-PCCRTP_R52 Site.CaptureRequirementIfIsTrue( isVerifyR52, 52, @"[In Appendix A: Product Behavior] <7> Section 3.2:The HTTP/1.1 server in Windows Server 2008 R2 sends a PeerDist-encoded response only when the response contains an ETag header field or a Last-Modified header field or both header fields."); } #endregion #region MS-PCCRTP_R54 if (PCCRTPServerAdapter.SutOsVersion == OSVersion.Win2K8R2) { bool isVerifyR54 = pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist") && !pccrtpResponse.ContentInfo.Equals(null); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R54. The HTTP/1.1 server in Windows Server 2008 R2 does {0} use the algorithms and data structures defined in [MS-PCCRC].", isVerifyR54 ? string.Empty : "not"); // Verify MS-PCCRTP requirement: MS-PCCRTP_R54 Site.CaptureRequirementIfIsTrue( isVerifyR54, 54, @"[In Appendix A: Product Behavior]<9> Section 3.2.5.1: The HTTP/1.1 server in Windows Server 2008 R2 uses the algorithms and data structures defined in [MS-PCCRC] to generate the PeerDist Content Information only when it receives an HTTP/1.1 request. "); } #endregion #region MS-PCCRRP_R8001 bool isVerifyR8001 = pccrtpResponse.HttpHeader.ContainsKey(CONTENTENCODING) && pccrtpResponse.HttpHeader[CONTENTENCODING].Contains("peerdist"); // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRTP_R8001, the PeerDist content-encoding value is {0} specified in the Accept-Encoding and Content-Encoding header fields.", isVerifyR8001 ? string.Empty : "not "); // Verify MS-PCCRTP requirement: MS-PCCRTP_R8001 Site.CaptureRequirementIfIsTrue( isVerifyR8001, 8001, @"[In Message Syntax] The PeerDist content-encoding value can be specified in the Accept-Encoding and Content-Encoding header fields,as shown in the following examples: Content-Encoding: peerdist."); #endregion }
/// <summary> /// Generate PCCRTP response message to reply the client request. /// </summary> /// <param name="resourceLocator">The client request URI.</param> /// <param name="serverSecret">The server secret set on the server endpoint.</param> /// <returns>Returns the PCCRTP response message.</returns> public PccrtpResponse GenerateResponseMessage(string resourceLocator, string serverSecret) { PccrtpResponse pccrtpResponse = new PccrtpResponse(); Dictionary<string, string> tempHttpHeader = new Dictionary<string, string>(); HashGeneration hashHelp = new HashGeneration(serverSecret, dwHashAlgo_Values.SHA256); byte[] fileData = PccrcUtility.ReadFile(resourceLocator); Content_Information_Data_Structure contentInfo = hashHelp.GenerateContentInformation(fileData); tempHttpHeader.Add(CONTENTENCODING, "peerdist"); tempHttpHeader.Add(XP2PPEERDIST, "Version=1.0, ContentLength=" + fileData.Length); pccrtpResponse.HttpHeader = tempHttpHeader; pccrtpResponse.PayloadData = contentInfo.ToByteArray(); return pccrtpResponse; }
/// <summary> /// Verify Segment Identifiers (HoHoDK) and Keys defined in section 2.2. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentIdentifiersAndKeys(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R26 bool isVerifyR26 = pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V1 || pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V2 || pccrtpResponse.ContentInfo.dwHashAlgo == dwHashAlgo_Values.V3; // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R26. the dwhashAlgo of hash is {0}", pccrtpResponse.ContentInfo.dwHashAlgo); // Verify MS-PCCRTP requirement: MS-PCCRC_R26 Site.CaptureRequirementIfIsTrue( isVerifyR26, 26, @"[In Segment Identifiers (HoHoDk) and Keys] Notation: Hash: The input hash function, which MUST be one of the hash functions listed in section 2.3."); #endregion #region MS-PCCRC_R37 bool isVerifyR37 = true; if (pccrtpResponse.ContentInfo.segments != null && pccrtpResponse.ContentInfo.blocks != null) { for (int i = 0; i < pccrtpResponse.ContentInfo.segments.Length; i++) { if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData == null || pccrtpResponse.ContentInfo.segments[i].SegmentSecret == null) { isVerifyR37 = false; break; } } } else { isVerifyR37 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R37. BlockHashes, SegmentHashOfData , SegmentSecret are {0}inclueded in the Content Information Data Structure.", isVerifyR37 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R37 Site.CaptureRequirementIfIsTrue( isVerifyR37, 37, @"[In Segment Identifiers (HoHoDk) and Keys] ContentInfo includes only the list of block hashes, the HoD, and Kp."); #endregion #region MS-PCCRC_R3701 // Verify MS-PCCRC requirement: MS-PCCRC_R3701 // The ContentInfo is parsed according the definition of Content Information Data Structure by the stack. // If ContentInfo improperly includes Ke and HoHoDk, then an exception will be thrown in the stack layer. // The program runs into here which has indicated that Ke and HoHoDk are not included in ContentInfo. // So MS-PCCRC_R3701 is captured directly. Site.CaptureRequirement( 3701, @"[In Segment Identifiers (HoHoDk) and Keys]Ke and HoHoDk are not included in ContentInfo."); #endregion }
/// <summary> /// Verify SegmentDescription defined in section 2.3.1.1. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentDescription(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R67 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R67, the actual number of SegmentDescription fields in segments field is {0}", pccrtpResponse.ContentInfo.segments.Length); // Verify MS-PCCRC requirement: MS-PCCRC_R67 Site.CaptureRequirementIfAreEqual<uint>( pccrtpResponse.ContentInfo.cSegments, (uint)pccrtpResponse.ContentInfo.segments.Length, 67, @"[In SegmentDescription] The segments field is composed of a number cSegments of SegmentDescription fields."); #endregion #region MS-PCCRC_R69 bool isVerifyR69 = true; for (int i = 0; i < pccrtpResponse.ContentInfo.cSegments - 1; i++) { if (pccrtpResponse.ContentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE) { isVerifyR69 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R69, the actual size of every segment except for the last segment is {0}32 megabytes", isVerifyR69 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R69 Site.CaptureRequirementIfIsTrue( isVerifyR69, 69, @"[In SegmentDescription] Every segment except for the last segment must be exactly 32 megabytes in size."); #endregion int hashLength = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; break; case dwHashAlgo_Values.V3: hashLength = 64; break; default: break; } #region MS-PCCRC_R74 bool isVerifyR74 = true; bool isVerifyR77 = true; bool isVerifyR79 = true; bool isVerifyR83 = true; bool isVerifyR76 = true; for (int i = 1; i < pccrtpResponse.ContentInfo.cSegments; i++) { ulong offset = pccrtpResponse.ContentInfo.segments[i - 1].ullOffsetInContent + pccrtpResponse.ContentInfo.segments[i - 1].cbSegment; if (pccrtpResponse.ContentInfo.segments[i].ullOffsetInContent != offset) { isVerifyR74 = false; } if (pccrtpResponse.ContentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE) { isVerifyR77 = false; } if (Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[i].cbBlockSize) != 4) { isVerifyR76 = false; } if (pccrtpResponse.ContentInfo.segments[i].SegmentHashOfData.Length != hashLength) { isVerifyR79 = false; } if (pccrtpResponse.ContentInfo.segments[i].SegmentSecret.Length != hashLength) { isVerifyR83 = false; } } if (pccrtpResponse.ContentInfo.segments[0].ullOffsetInContent != 0) { isVerifyR74 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R74, the ullOffsetInContent in every SegmentDescription field is {0}content offset at which the start of the segment begins.", isVerifyR74 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R74 Site.CaptureRequirementIfIsTrue( isVerifyR74, 74, @"[In SegmentDescription] ullOffsetInContent (8 bytes): Content offset at which the start of the segment begins."); #endregion #region MS-PCCRC_R75 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R75. The actual size of the cbSegment is {0}.", Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment)); // Verify MS-PCCRC requirement: MS-PCCRC_R75 Site.CaptureRequirementIfAreEqual<int>( 4, Marshal.SizeOf(pccrtpResponse.ContentInfo.segments[0].cbSegment), 75, @"[In SegmentDescription] cbSegment (4 bytes): Total number of bytes in the segment, regardless of how many of those bytes intersect the content range."); #endregion #region MS-PCCRC_R76 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R76. The actual size of the cbBlockSize is {0}4 bytes.", isVerifyR76 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R76 Site.CaptureRequirementIfIsTrue( isVerifyR76, 76, @"[In SegmentDescription] cbBlockSize (4 bytes): Length of a content block within this segment, in bytes."); #endregion #region MS-PCCRC_R77 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R77, the block size of every segment is {0}65536 bytes", isVerifyR77 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R77 Site.CaptureRequirementIfIsTrue( isVerifyR77, 77, @"[In SegmentDescription] cbBlockSize (4 bytes): Every segment MUST use the block size of 65536 bytes."); #endregion #region MS-PCCRC_R79 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R79, the actual SegmentHashOfData is {0} of length 32", isVerifyR79 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R79 Site.CaptureRequirementIfIsTrue( isVerifyR79, 79, @"[In SegmentDescription] SegmentHashOfData (variable): The hash is of length 32 if dwHashAlgo at the start of the Content Information was 0x800C = SHA-256."); #endregion #region MS-PCCRC_R83 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R83, the actual length of the SegmentSecret is {0}", hashLength); // Verify MS-PCCRC requirement: MS-PCCRC_R83 Site.CaptureRequirementIfIsTrue( isVerifyR83, 83, @"[In SegmentDescription] SegmentSecret (variable):The hash is of length 32 if dwHashAlgo at the start of the Content Information was 0x800C = SHA-256."); #endregion }
/// <summary> /// Verify Content, Segments, and Blocks defined in section 2.1. /// </summary> /// <param name="pccrtpResponse">The HTTP resopnse.</param> private void VerifyContentSegmentsBlocks(PccrtpResponse pccrtpResponse) { Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo; #region MS-PCCRC_R3 // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R3.segment is {0} type", pccrtpResponse.HttpHeader[ACCEPTRANGES]); bool isVerifyR3 = pccrtpResponse.HttpHeader[ACCEPTRANGES].Equals("bytes"); // Verify MS-PCCRC requirement: MS-PCCRC_R3 Site.CaptureRequirementIfIsTrue( isVerifyR3, 3, @"[In Content, Segments, and Blocks] Each segment is a binary string."); #endregion #region MS-PCCRC_R10 bool isVerifyR10 = true; for (int i = 0; i < contentInfo.cSegments - 1; i++) { if (contentInfo.segments[i].cbBlockSize != STANDARDBBLOCKSIZE) { isVerifyR10 = false; break; } } // Check for the last block in the last segment, which may be shorter than the standard block size (64 KB). if (contentInfo.segments[contentInfo.cSegments - 1].cbBlockSize > STANDARDBBLOCKSIZE) { isVerifyR10 = false; } // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R10. Each block size is {0} 64 kilobytes", isVerifyR10 ? string.Empty : "not"); // Verify MS-PCCRC requirement: MS-PCCRC_R10 Site.CaptureRequirementIfIsTrue( isVerifyR10, 10, @"[In Content, Segments, and Blocks] Each block is a binary string of a fixed size (64 kilobytes), except for the last block in the last segment, which again may be shorter."); #endregion #region MS-PCCRC_R4 string allLength = string.Empty; if (pccrtpResponse.HttpHeader.ContainsKey(CONTENTRANGE)) { // Get the value of content length in the response for partial request. allLength = pccrtpResponse.HttpHeader[CONTENTRANGE]; allLength = allLength.Substring(allLength.IndexOf('/') + 1); } else if (pccrtpResponse.HttpHeader.ContainsKey(XP2PPEERDIST)) { // Get the value of content length in the response for full request. allLength = pccrtpResponse.HttpHeader[XP2PPEERDIST]; allLength = allLength.Substring(allLength.LastIndexOf('=') + 1); } bool isVerifyR4 = true; long contentLength = 0; try { contentLength = Convert.ToInt64(allLength); } catch (FormatException e) { throw new FormatException(e.ToString()); } long lastSegmentLength = 0; for (int i = 0; i < contentInfo.cSegments; i++) { // If there are multiple segments, check each segment is of a standard size (32 MB). if (contentLength > STANDARDSEGMENTSIZE) { if (contentInfo.segments[i].cbSegment != STANDARDSEGMENTSIZE) { isVerifyR4 = false; break; } contentLength -= STANDARDSEGMENTSIZE; } else { // Check for the last segment, which may be shorter than the standard segment size (32 MB). if (contentLength != contentInfo.segments[i].cbSegment) { if (i > 0) { lastSegmentLength = contentLength; } isVerifyR4 = false; break; } } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, "Verify MS-PCCRC_R4.segment size is {0}32 megabytes except possibly the last segment", isVerifyR4 ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R4 Site.CaptureRequirementIfIsTrue( isVerifyR4, 4, @"[In Content, Segments, and Blocks] Each segment is of a standard size (32 megabytes), except possibly the last segment which may be smaller if the content size is not a multiple of the standard segment size."); #endregion // MS-PCCRC_R63 is blocked by TDI(Techical Document Issue) about inaccurate definition of // dwReadBytesInLastSegment if the HTTP request is a range retrieval request. if (bool.Parse(Site.Properties.Get("PCCRC.IsTDI.65999.Fixed"))) { #region MS-PCCRC_R63 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R63, the actual value of the dwReadBytesInLastSegment is {0}", contentInfo.dwReadBytesInLastSegment); // Verify MS-PCCRC requirement: MS-PCCRC_R63 Site.CaptureRequirementIfAreEqual<long>( lastSegmentLength, contentInfo.dwReadBytesInLastSegment, 63, @"[In Content Information Data Structure Version 1.0] dwReadBytesInLastSegment (4 bytes): Total number of bytes of the content range which lie within the final segment in the Content Information data structure."); #endregion } }
/// <summary> /// Verify SegmentContentBlocks defined in section 2.3.1.2. /// </summary> /// <param name="pccrtpResponse">The HTTP response.</param> private void VerifySegmentContentBlocks(PccrtpResponse pccrtpResponse) { #region MS-PCCRC_R86 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R86, the actual number of SegmentContentBlocks fields in blocks field is {0}", pccrtpResponse.ContentInfo.blocks.Length); // Verify MS-PCCRC requirement: MS-PCCRC_R86 Site.CaptureRequirementIfAreEqual<uint>( pccrtpResponse.ContentInfo.cSegments, (uint)pccrtpResponse.ContentInfo.blocks.Length, 86, @"[In SegmentContentBlocks] The blocks field contains a number cSegments of SegmentContentBlocks fields."); #endregion #region MS-PCCRC_R89 bool isVerifyR89 = true; int hashLength = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; break; case dwHashAlgo_Values.V3: hashLength = 64; break; default: break; } foreach (SegmentContentBlocks segContentBlocks in pccrtpResponse.ContentInfo.blocks) { if (segContentBlocks.BlockHashes.Length != segContentBlocks.cBlocks * hashLength) { isVerifyR89 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R89, the actual size of BlockHashes field is {0} cBlocks * {1}", isVerifyR89 ? string.Empty : "not ", hashLength); // Verify MS-PCCRC requirement: MS-PCCRC_R89 Site.CaptureRequirementIfIsTrue( isVerifyR89, 89, @"[In SegmentContentBlocks] BlockHashes (variable):The size of this field is cBlocks * (32, 48 or 64, depending on which hash was used)."); #endregion #region MS-PCCRC_R12 // The BlockHashes field is parsed according the cBlocks and the hash algorithm by the stack. // If MS-PCCRC_R89 is verified successfully, it indicates that the BlockHashes is the hash list // of each block in the order the block in the segment.So MS-PCCRC_R12 is captured directly. Site.CaptureRequirement( 12, @"[In Content, Segments, and Blocks] Blocks within a segment are identified by their progressive index within the segment (Block 0 is the first block in the segment, Block 1 the second, and so on)."); #endregion }
/// <summary> /// Verify Data Structure of Content Information defined in section 2.3. /// </summary> /// <param name="pccrtpResponse">The HTTP resopnse.</param> private void VerifyDataStructure(PccrtpResponse pccrtpResponse) { Content_Information_Data_Structure contentInfo = pccrtpResponse.ContentInfo; #region MS-PCCRC_R58 int hashLength = 0; int valueOfDwHashAlgo = 0; switch (pccrtpResponse.ContentInfo.dwHashAlgo) { case dwHashAlgo_Values.V1: valueOfDwHashAlgo = 0x0000800C; hashLength = 32; break; case dwHashAlgo_Values.V2: hashLength = 48; valueOfDwHashAlgo = 0x0000800D; break; case dwHashAlgo_Values.V3: hashLength = 64; valueOfDwHashAlgo = 0x0000800E; break; default: break; } // Add the debug information. Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R58, the actual length of dwHashAlgo is: {0}", Marshal.SizeOf(valueOfDwHashAlgo)); // Verify MS-PCCRC requirement: MS-PCCRC_R58 Site.CaptureRequirementIfAreEqual<int>( 4, Marshal.SizeOf(valueOfDwHashAlgo), 58, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): Hash algorithm to use. <2> "); #endregion #region MS-PCCRC_R581 bool isVerifyR581 = valueOfDwHashAlgo == 0x0000800C || valueOfDwHashAlgo == 0x0000800D || valueOfDwHashAlgo == 0x0000800E; // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R581, the actual value of dwHashAlgo is 0x{0:X8}.", valueOfDwHashAlgo); // Verify MS-PCCRC requirement: MS-PCCRC_R581 Site.CaptureRequirementIfIsTrue( isVerifyR581, 581, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): MUST be one of the following values:0x0000800C,0x0000800D,0x0000800E."); #endregion #region MS-PCCRC_R59 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R59, , the actual value of dwHashAlgo is 0x{0:X8}.", valueOfDwHashAlgo); // Verify MS-PCCRC requirement: MS-PCCRTP_R59 Site.CaptureRequirementIfAreEqual<int>( 0x0000800C, valueOfDwHashAlgo, 59, @"[In Content Information Data Structure Version 1.0] dwHashAlgo (4 bytes): When use the SHA-256 hash algorithm, the value is 0x0000800C."); #endregion #region MS-PCCRC_R54 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R54, all fields are {0}in little-endian byte order", BitConverter.IsLittleEndian ? string.Empty : "not "); // Verify MS-PCCRC requirement: MS-PCCRC_R54 Site.CaptureRequirementIfIsTrue( BitConverter.IsLittleEndian, 54, @"[In Content Information Data Structure Version 1.0] All fields are in little-endian byte order."); #endregion #region MS-PCCRC_R57 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R57, the actual value of Version is 0x{0:X8}", contentInfo.Version); // Verify MS-PCCRC requirement: MS-PCCRTP_R57 Site.CaptureRequirementIfAreEqual<int>( 0x0100, contentInfo.Version, 57, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): MUST be 0x0100."); #endregion #region MS-PCCRC_R53 // The Version is parsed at the first 2 byte word in Content Information by stack. // If MS-PCCRC_R57 is verified successfully, MS-PCCRC_R53 is verified and so captured directly. Site.CaptureRequirement( 53, @"[In Content Information Data Structure Version 1.0] Content Information starts with a single 2 byte WORD value representing the data structure version."); #endregion #region MS-PCCRC_R56 // The Version is parsed at the first 2 byte word in Content Information by stack. // If MS-PCCRC_R57 is verified successfully, it indicates that the low byte is the minor version number // and the high byte is the major version number. Site.CaptureRequirement( 56, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): The low byte is the minor version number and the high byte is the major version number."); #endregion #region MS-PCCRC_R55 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R55, the actual size of the Version is {0}", Marshal.SizeOf(contentInfo.Version)); // Verify MS-PCCRC requirement: MS-PCCRTP_R55 Site.CaptureRequirementIfAreEqual<int>( 2, Marshal.SizeOf(contentInfo.Version), 55, @"[In Content Information Data Structure Version 1.0] Version (2 bytes): Content Information version (0x0100 is version 1.0)."); #endregion #region MS-PCCRC_R64 // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R64, the actual value of the cSegments is {0}", contentInfo.cSegments); // Verify MS-PCCRC requirement: MS-PCCRC_R64 Site.CaptureRequirementIfAreEqual<int>( contentInfo.segments.Length, (int)contentInfo.cSegments, 64, @"[In Content Information Data Structure Version 1.0] cSegments (4 bytes): The number of segments which intersect the content range and hence are contained in the Content Information data structure."); #endregion #region MS-PCCRC_R65 bool isVerifyR65 = true; for (int i = 0; i < contentInfo.cSegments; i++) { if (contentInfo.segments[i].cbBlockSize == STANDARDBBLOCKSIZE && contentInfo.segments[i].SegmentHashOfData.Length == hashLength && contentInfo.segments[i].SegmentSecret.Length == hashLength) { isVerifyR65 = true; } else { isVerifyR65 = false; break; } } // Add the debug information Site.Log.Add( LogEntryKind.Debug, @"Verify MS-PCCRC_R65, the segments variable {0} contain the Segment start offset, length, block size, SegmentHashofData and SegmentSecret for each segment.", isVerifyR65 ? string.Empty : "does't"); // Verify MS-PCCRC requirement: MS-PCCRC_R65 Site.CaptureRequirementIfIsTrue( isVerifyR65, 65, @"[In Content Information Data Structure Version 1.0] segments (variable): Segment start offset, length, block size, SegmentHashofData and SegmentSecret for each segment."); #endregion }
/// <summary> /// Send a PCCRTP request message and receive a PCCRTP response message. /// </summary> /// <param name="httpVersion">Indicates the HTTP version type used.</param> /// <param name="isRequestPartialContent">Indicates it is requesting partical content or not.</param> /// <param name="uri">Indicates the URI on the SUT requested by the client.</param> /// <returns>Return the PCCRTP response message received.</returns> public PccrtpResponse SendPccrtpRequestMessage( HttpVersionType httpVersion, bool isRequestPartialContent, string uri) { PccrtpRequest pccrtpRequest = new PccrtpRequest(); PccrtpResponse pccrtpResponse = new PccrtpResponse(); string serverAddress = this.GetProperty("Environment.ContentServer.MachineName"); int port = int.Parse(this.GetProperty("Environment.ContentServer.HTTP.Port")); int timeOut = (int)TimeSpan.FromSeconds( double.Parse(this.GetProperty("PCCRTP.Protocol.TimeOut"))).TotalMilliseconds; int rangeFrom = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeFrom")); int rangeTo = int.Parse(this.GetProperty("PCCRTP.Protocol.RangeTo")); if (isRequestPartialContent) { pccrtpRequest = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri); pccrtpResponse = this.pccrtpClientStack.SendHttpRequest( httpVersion, pccrtpRequest, timeOut, rangeFrom, rangeTo); } else { pccrtpRequest = this.pccrtpClientStack.CreatePccrtpRequest(serverAddress, port, uri); pccrtpResponse = this.pccrtpClientStack.SendHttpRequest(httpVersion, pccrtpRequest, timeOut); } if (pccrtpResponse.HttpResponse.ContentEncoding.Equals("peerdist")) { PccrtpBothRoleCapture.VerifyTransport(pccrtpResponse.HttpResponse.ProtocolVersion.ToString()); PccrtpBothRoleCapture.VerifyPccrtpCommonHeader(pccrtpResponse.HttpHeader); this.VerifyPccrtpResponse(pccrtpResponse); this.VerifyContentInfomationStructure(pccrtpResponse); } return pccrtpResponse; }