Skip to content
This repository was archived by the owner on Jun 5, 2019. It is now read-only.

Commit 679a89b

Browse files
committed
Merge pull request #304 from smaillet-ms/HttpClient-sample
Added HttpClient Sample.
2 parents a192fe6 + 0195ceb commit 679a89b

File tree

11 files changed

+844
-0
lines changed

11 files changed

+844
-0
lines changed
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2015 Microsoft Corporation
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
*/
24+
using Microsoft.SPOT;
25+
using System;
26+
using System.IO;
27+
using System.Net;
28+
using System.Net.Sockets;
29+
using System.Security.Cryptography.X509Certificates;
30+
using System.Text;
31+
using System.Threading;
32+
33+
/// This program demonstrates how to use the .NET Micro Framework HTTP classes
34+
/// to create a simple HTTP client that retrieves pages from several different
35+
/// websites, including secure sites.
36+
namespace HttpClientSample
37+
{
38+
public static class MyHttpClient
39+
{
40+
// Ideally the preferred time service name should be stored in some form of persistent memory
41+
private const string TimeServiceName = "time.nist.gov";
42+
43+
// Ideally the timeszone offset should be stored in some form of persistent memory
44+
private const int TimeZoneOffset = -7 * 60; // [ UTC -8 timezone (+1 for DST ) ]
45+
46+
private static NetworkStateMonitor NetMonitor = new NetworkStateMonitor( );
47+
private static Decoder UTF8decoder = Encoding.UTF8.GetDecoder( );
48+
49+
/// <summary>Retrieves pages from a Web servers, using a simple HTTP requests</summary>
50+
public static void Main( )
51+
{
52+
// Root CA Certificate needed to validate HTTPS servers.
53+
var validButIncorrectCert = new X509Certificate( Resources.GetBytes( Resources.BinaryResources.VerisignCA ) );
54+
var validAndCorrectCert = new X509Certificate( Resources.GetBytes( Resources.BinaryResources.DigiCert ) );
55+
56+
X509Certificate[ ] willFailCerts = { validButIncorrectCert };
57+
X509Certificate[ ] willSucceedCerts = { validButIncorrectCert, validAndCorrectCert };
58+
59+
NetMonitor.WaitForIpAddress();
60+
TimeServiceManager.InitTimeService( TimeServiceName, TimeZoneOffset );
61+
Debug.Print(" Time is: " + DateTime.Now.ToString());
62+
63+
// Print the HTTP data from each of the following pages.
64+
65+
// Response Should be a simple re-direct plus "moved" message
66+
Debug.Print( "Fetching data from: http://autos.msn.com/default.aspx" );
67+
PrintHttpData( "http://autos.msn.com/default.aspx", null );
68+
69+
// Test SSL connection with no certificate verification
70+
// NOTE: This is not expected to generate an error or fail condition.
71+
// Since no certificates were provided no verification is performed.
72+
// This may or may not be an issue depending on circumstances. It is
73+
// certainly useful during development before a valid cert is available
74+
// for a server, however it is generally not recommended for production
75+
// systems as it opens the door to "man in the middle" type attacks.
76+
Debug.Print( "Fetching data from: https://github.com/NETMF/netmf-interpreter no cert validation" );
77+
PrintHttpData( "https://github.com/NETMF/netmf-interpreter", null );
78+
79+
// Read from secure webpages by using the provided Root
80+
// certificates that are stored in the Resource.resx file.
81+
Debug.Print( "Fetching data from: https://github.com/NETMF/netmf-interpreter with valid cert validation" );
82+
PrintHttpData( "https://github.com/NETMF/netmf-interpreter", willSucceedCerts );
83+
84+
// This is expected to generate a WebException since the array of certificates
85+
// provided doesn't include any that can be used to validate the site's certificate
86+
try
87+
{
88+
Debug.Print( "Fetching data from: https://github.com/NETMF/netmf-interpreter with invalid cert validation" );
89+
PrintHttpData( "https://github.com/NETMF/netmf-interpreter", willFailCerts );
90+
}
91+
catch( WebException ex )
92+
{
93+
var innerException = ex.InnerException as SocketException;
94+
if( innerException != null && innerException.ErrorCode == 1 )
95+
{
96+
Debug.Print( "Got expected Exception..." );
97+
}
98+
}
99+
}
100+
101+
/// <summary>
102+
/// Prints the HTTP Web page from the given URL and status data while
103+
/// receiving the page.
104+
/// </summary>
105+
/// <param name="url">The URL of the page to print.</param>
106+
/// <param name="caCerts">The root CA certificates that are required for
107+
/// validating a secure website (HTTPS).</param>
108+
public static void PrintHttpData( string url, X509Certificate[ ] caCerts )
109+
{
110+
try
111+
{
112+
// Create an HTTP Web request.
113+
HttpWebRequest request = WebRequest.Create( url ) as HttpWebRequest;
114+
Debug.Assert( request != null );
115+
116+
// Assign the certificates. If this is null, then no
117+
// validation of server certificates is performed.
118+
request.HttpsAuthentCerts = caCerts;
119+
120+
// Get a response from the server.
121+
// process the response
122+
using( WebResponse resp = request.GetResponse( ) )
123+
{
124+
ProcessResponse( resp );
125+
}
126+
127+
}
128+
catch( WebException ex )
129+
{
130+
var innerException = ex.InnerException as SocketException;
131+
if( caCerts != null && innerException != null && innerException.ErrorCode == 1 )
132+
{
133+
throw;
134+
}
135+
Debug.Print( ex.Message );
136+
}
137+
}
138+
139+
private static void ProcessResponse( WebResponse resp )
140+
{
141+
// Get the network response stream to read the page data.
142+
Stream respStream = resp.GetResponseStream( );
143+
StringBuilder page = new StringBuilder( );
144+
byte[ ] byteData = new byte[ 4096 ];
145+
int bytesRead = 0;
146+
int totalBytes = 0;
147+
148+
// allow up to 15 seconds as a timeout for reading the stream
149+
respStream.ReadTimeout = 15000;
150+
151+
// If the content length was provided, read exactly that amount of
152+
// data; otherwise, read until there is nothing left to read.
153+
if( resp.ContentLength != -1 )
154+
{
155+
for( int dataRem = ( int )resp.ContentLength; dataRem > 0; )
156+
{
157+
bytesRead = ReadData( respStream, byteData );
158+
if( bytesRead == 0 )
159+
{
160+
Debug.Print( "Error: Received " + ( resp.ContentLength - dataRem ) + " Out of " + resp.ContentLength );
161+
break;
162+
}
163+
dataRem -= bytesRead;
164+
totalBytes += bytesRead;
165+
AppendPageData( page, byteData, bytesRead, totalBytes );
166+
}
167+
}
168+
else
169+
{
170+
// Read until the end of the data is reached.
171+
while( true )
172+
{
173+
bytesRead = ReadData( respStream, byteData );
174+
175+
// Zero bytes indicates the connection has been closed
176+
// by the server or some other error, either way there's
177+
// no more data to process.
178+
if( bytesRead == 0 )
179+
{
180+
break;
181+
}
182+
totalBytes += bytesRead;
183+
AppendPageData( page, byteData, bytesRead, totalBytes );
184+
}
185+
186+
Debug.Print( "Total bytes downloaded in message body : " + totalBytes );
187+
}
188+
189+
// Display the page results.
190+
Debug.Print( page.ToString( ) );
191+
}
192+
193+
private static int ReadData( Stream respStream, byte[ ] byteData )
194+
{
195+
// If the Read method times out, it throws an exception,
196+
// which is expected for Keep-Alive streams because the
197+
// connection isn't terminated.
198+
int bytesRead;
199+
try
200+
{
201+
bytesRead = respStream.Read( byteData, 0, byteData.Length );
202+
}
203+
catch( IOException )
204+
{
205+
bytesRead = 0;
206+
}
207+
208+
return bytesRead;
209+
}
210+
211+
private static void AppendPageData( StringBuilder page
212+
, byte[ ] byteData
213+
, int bytesRead
214+
, int totalBytes
215+
)
216+
{
217+
// Convert from bytes to chars, and add to the page.
218+
int byteUsed;
219+
int charUsed = 0;
220+
bool completed = false;
221+
var charData = new char[ 4096 ];
222+
223+
while( !completed )
224+
{
225+
UTF8decoder.Convert( byteData
226+
, 0
227+
, bytesRead
228+
, charData
229+
, 0
230+
, bytesRead
231+
, true
232+
, out byteUsed
233+
, out charUsed
234+
, out completed
235+
);
236+
}
237+
page.Append( new string( charData, 0, charUsed ) );
238+
239+
// Display the page download status.
240+
Debug.Print( "Bytes Read Now: " + bytesRead + " Total: " + totalBytes );
241+
}
242+
}
243+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
3+
<PropertyGroup>
4+
<AssemblyName>HTTPClient</AssemblyName>
5+
<OutputType>Exe</OutputType>
6+
<RootNamespace>HttpClientSample</RootNamespace>
7+
<ProjectTypeGuids>{b69e3092-b931-443c-abe7-7e7b65f2a37f};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
8+
<ProductVersion>9.0.21022</ProductVersion>
9+
<SchemaVersion>2.0</SchemaVersion>
10+
<ProjectGuid>{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}</ProjectGuid>
11+
<TargetFrameworkVersion>v4.4</TargetFrameworkVersion>
12+
<NetMfTargetsBaseDir Condition="'$(NetMfTargetsBaseDir)'==''">$(MSBuildExtensionsPath32)\Microsoft\.NET Micro Framework\</NetMfTargetsBaseDir>
13+
</PropertyGroup>
14+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
15+
<DebugSymbols>true</DebugSymbols>
16+
<DebugType>full</DebugType>
17+
<Optimize>false</Optimize>
18+
<OutputPath>bin\Debug\</OutputPath>
19+
<DefineConstants>DEBUG;TRACE</DefineConstants>
20+
<ErrorReport>prompt</ErrorReport>
21+
<WarningLevel>4</WarningLevel>
22+
</PropertyGroup>
23+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
24+
<DebugType>pdbonly</DebugType>
25+
<Optimize>true</Optimize>
26+
<OutputPath>bin\Release\</OutputPath>
27+
<DefineConstants>TRACE</DefineConstants>
28+
<ErrorReport>prompt</ErrorReport>
29+
<WarningLevel>4</WarningLevel>
30+
</PropertyGroup>
31+
<ItemGroup>
32+
<Compile Include="NetworkStateMonitor.cs" />
33+
<Compile Include="Properties\AssemblyInfo.cs" />
34+
<Compile Include="HttpClient.cs" />
35+
<Compile Include="Resources.Designer.cs">
36+
<AutoGen>True</AutoGen>
37+
<DesignTime>True</DesignTime>
38+
<DependentUpon>Resources.resx</DependentUpon>
39+
</Compile>
40+
<Compile Include="TimeServiceManager.cs" />
41+
</ItemGroup>
42+
<ItemGroup>
43+
<Reference Include="Microsoft.SPOT.Graphics" />
44+
<Reference Include="Microsoft.SPOT.IO" />
45+
<Reference Include="Microsoft.SPOT.Native" />
46+
<Reference Include="Microsoft.SPOT.Time" />
47+
<Reference Include="System" />
48+
<Reference Include="System.IO" />
49+
<Reference Include="System.Http" />
50+
<Reference Include="System.Net.Security" />
51+
<Reference Include="Microsoft.SPOT.Net" />
52+
<Reference Include="Microsoft.SPOT.Net.Security" />
53+
</ItemGroup>
54+
<ItemGroup>
55+
<EmbeddedResource Include="Resources.resx">
56+
<SubType>Designer</SubType>
57+
<Generator>ResXFileCodeGenerator</Generator>
58+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
59+
</EmbeddedResource>
60+
</ItemGroup>
61+
<ItemGroup>
62+
<None Include="Resources\DigiCert.cer" />
63+
<None Include="Resources\VerisignCA.cer" />
64+
</ItemGroup>
65+
<ItemGroup>
66+
<Content Include="readme.txt" />
67+
</ItemGroup>
68+
<Import Condition="EXISTS('$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets')" Project="$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets" />
69+
<Import Condition="!EXISTS('$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets')" Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
70+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.23107.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClient", "HttpClient.csproj", "{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
17+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Release|Any CPU.ActiveCfg = Release|Any CPU
18+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Release|Any CPU.Build.0 = Release|Any CPU
19+
{9387BD77-6E80-40F6-9DB0-11FAEFBD4074}.Release|Any CPU.Deploy.0 = Release|Any CPU
20+
EndGlobalSection
21+
GlobalSection(SolutionProperties) = preSolution
22+
HideSolutionNode = FALSE
23+
EndGlobalSection
24+
EndGlobal

0 commit comments

Comments
 (0)