Showing posts with label character. Show all posts
Showing posts with label character. Show all posts

Saturday, March 31, 2012

System.FormatException: Invalid character in a Base-64 string...

Problem:
Enter the URL to a small image file (or any file), retrieve the file and encode the data as base64, then decode the base64 to get the original files data.

When the page below is executed, the file is retrieved and encoded, however when the decode_base64() subroutine is called, the system displays the following exception:

System.FormatException: Invalid character in a Base-64 string.
at System.Convert.FromBase64String(String s)
at ASP.test_base64_aspx.decode_base64()

Obviously, there is an invalid character in the Base-64 string -- the strange thing is if I increase "k_buf_size" from 4096 to something like 32000 (in the encode_base64 subroutine) and execute the page everything works just fine!!

So my question is, why will this code NOT work with smaller buffer sizes?? Hopefully, I have made a simple programming error that someone will point out as I have stared at this for too long ...

ANY help would be appreciated!

<%@dotnet.itags.org. Page Language="VB" Explicit="true" Strict="true" Trace="true" %>

<%@dotnet.itags.org. Import Namespace="System.IO" %>
<%@dotnet.itags.org. Import Namespace="System.Data" %>
<%@dotnet.itags.org. Import Namespace="System.Net" %>

<script language="VB" runat="server">

' The base64 encoded data ...
private m_encoded_data as StringBuilder

' The size of the file that was encoded ...
private m_file_size as Integer


'----------------
'
private sub do_test( Sender as Object, e as EventArgs )

' Init ...
m_encoded_data = new StringBuilder()
m_file_size = 0

' Attempt to encode the input file ...
encode_base64()

' If a file was encoded, attempt to decode ...
if ( m_encoded_data.length > 0 ) then

decode_base64()

end if

end sub


'----------------
'
private sub encode_base64()

const k_buf_size as Integer = 4096

dim bytes_read as Integer
dim n as Integer

dim err_msg as String
dim s as String
dim url as String

dim sr as Stream

dim wc as WebClient

Trace.Warn( ">", "==============" )
Trace.Warn( ">", "encode_base64:" )

' Get URL ...
url = fld_url.text.Trim()
if ( url.length = 0 )
exit sub
end if

' Attempt to get the data file and encode as base 64 ...
try

wc = Nothing
sr = Nothing
m_file_size = 0

' Create space to hold data ...
dim data_array( k_buf_size ) as Byte

' Create web client ...
wc = new WebClient()

' Create stream from URL ...
sr = wc.OpenRead( url )

' Loop to encode data stream ...

' Read a chunk from the data steam into array ...
bytes_read = sr.Read( data_array, 0, k_buf_size )

do while ( bytes_read > 0 )

Trace.Warn( ">", "bytes_read = " & bytes_read.ToString() )

m_file_size = m_file_size + bytes_read

' Convert data chunk to base 64 string. Remove any padding characters (=)
' that may have been added ...
s = System.Convert.ToBase64String( data_array, 0, bytes_read )
n = s.IndexOf( "=" )

if ( n > 0 ) then
m_encoded_data.Append( s.Substring( 0, n ) )
else
m_encoded_data.Append( s )
end if

bytes_read = sr.Read( data_array, 0, k_buf_size )

loop

' Encoded output length must be a multiple of 4 bytes, so pad if necessary ...
n = m_encoded_data.length Mod 4
if ( n <> 0 ) then
m_encoded_data.Append( new String( "="C, 4 - n ) )
end if

' Clean up ...
data_array = Nothing

Trace.Warn( ">", "File size = " & m_file_size.ToString() )
Trace.Warn( ">", "Encoded data length = " & m_encoded_data.length.ToString() )

catch ex as Exception
Trace.Warn( ">", ex.ToString() )

finally
if ( not sr is Nothing ) then
sr.Close()
sr = Nothing
end if
if ( not wc is Nothing ) then
wc.Dispose()
wc = Nothing
end if

end try

end sub


'----------------
'
private sub decode_base64()

dim data_array() as Byte

Trace.Warn( ">", "==============" )
Trace.Warn( ">", "decode_base64:" )

' Attempt to decode from base64 ...
try

data_array = Convert.FromBase64String( m_encoded_data.ToString() )

Trace.Warn( ">", "data_array.length = " & data_array.length.ToString() )

if ( data_array.length = m_file_size ) then
Trace.Warn( ">", "DECODE OK" )
else
Trace.Warn( ">", "DECODE FAILED!" )
end if

catch ex as Exception
Trace.Warn( ">", ex.ToString() )

end try

end sub
</script>
<html>
<head>
<title>Attempt to encode/decode using Base 64</title>
</head>
<body>
<blockquote>

<form runat="server">
Enter the URL to a file, preferably a small image JPG or GIF file.
<hr noshade size="1">
<table width="90%" border="0" cellpadding="2" cellspacing="1">
<tr>
<td width="20%" align="right" valign="top" >
URL:
</td>
<td width="80%" align="left" valign="top" >
<asp:TextBox id="fld_url" text="" size="100" maxlength="200" runat="server" />
</td>
</tr>
</table>
<hr noshade size="1">
<table width="90%" border="0" cellpadding="2" cellspacing="1">
<tr>
<td width="20%"> </td>
<td width="80%" valign="top">
<asp:Button OnClick="do_test" text="Do Base64 Test" runat="server" />
</td>
</tr>
</table>
</form>

</blockquote>
</body>
</html>

Ok - here is one solution (may not be the best, but it works)...

The problem with base 64 encoding is that one has to be careful when reading data in "chunks" and then encoding each chunk (as base 64) and then appending each chunk to form the final encoded string -- this is what I was doing initially. The code would work whenever I changed the buffer size to anything larger than the file being read, ie: whenever the entire file was read in one chunk. In any case, the solution is shown below for anyone that comes across this problem. Please note that the solution below limits the file sizes that can be encoded to 2 megabytes.

<%@. Page Language="VB" Explicit="true" Strict="true" Trace="true" %>

<%@. Import Namespace="System.IO" %>
<%@. Import Namespace="System.Data" %>
<%@. Import Namespace="System.Net" %>

<%@. Import Namespace="rentsys" %>

<script language="VB" runat="server">

' The base64 encoded data ...
private m_encoded_data as String

' The size of the file that was encoded ...
private m_file_size as Long


'----------------
'
private sub do_test( Sender as Object, e as EventArgs )

' Init ...
m_encoded_data = String.Empty
m_file_size = 0

' Attempt to encode the input file ...
encode_base64()

' If a file was encoded, attempt to decode ...
if ( m_encoded_data.length > 0 ) then

decode_base64()

end if

end sub


'----------------
'
private sub encode_base64()

' Maximum file size is 2 MB ...
const k_max_file_size as Long = 2000000

' Buffer used to read file in chunks ...
const k_data_buf_size as Integer = 4096
dim data_buf( k_data_buf_size ) as Byte

dim bytes_read as Integer

dim err_msg as String
dim s as String
dim url as String

dim ms as MemoryStream

dim sr as Stream

dim wc as WebClient


Trace.Warn( ">", "==============" )
Trace.Warn( ">", "encode_base64:" )

' Get URL ...
url = fld_url.text.Trim()
if ( url.length = 0 )
exit sub
end if


' Get the size of the remote file, unfortunately, the only way
' to reliably get this is to read the entire file. We could issue
' an HTTP HEAD request to get the content length, but some servers
' may not return file headers ...
try

wc = Nothing
sr = Nothing
m_file_size = 0

' Create web client ...
wc = new WebClient()

' Create stream from URL ...
sr = wc.OpenRead( url )

' Loop to determine file size ...
bytes_read = sr.Read( data_buf, 0, k_data_buf_size )
do while ( bytes_read > 0 )
m_file_size = m_file_size + bytes_read
bytes_read = sr.Read( data_buf, 0, k_data_buf_size )
loop

catch ex as Exception
Trace.Warn( ">", ex.ToString() )

finally
if ( not sr is Nothing ) then
sr.Close()
sr = Nothing
end if
if ( not wc is Nothing ) then
wc.Dispose()
wc = Nothing
end if

end try


' Check if we can handle the file size ...
Trace.Warn( ">", "File size = " & m_file_size.ToString() )

if ( m_file_size > k_max_file_size ) then
Trace.Warn( ">", "File size exceeds maximum allowed" )
exit sub
end if


' Attempt to read the file contents and encode as base 64 ...
try

wc = Nothing
sr = Nothing
ms = Nothing

' Create web client ...
wc = new WebClient()

' Create stream from URL ...
sr = wc.OpenRead( url )

' Create memory stream to hold file contents ...
ms = new MemoryStream()

' Loop to read data into memory stream. Note that we
' CANNOT convert each chunk read into base 64 and append
' to a string as this would lead to an invalid base 64
' string due to the nature of the algorithm and padding
' characters that would be present in the final string ...

bytes_read = sr.Read( data_buf, 0, k_data_buf_size )
do while ( bytes_read > 0 )

ms.Write( data_buf, 0, bytes_read )

bytes_read = sr.Read( data_buf, 0, k_data_buf_size )

loop

' Convert the data to base 64 ...
m_encoded_data = Convert.ToBase64String( ms.ToArray() )

catch ex as Exception
Trace.Warn( ">", ex.ToString() )

finally
if ( not ms is Nothing ) then
ms.Close()
ms = Nothing
end if
if ( not sr is Nothing ) then
sr.Close()
sr = Nothing
end if
if ( not wc is Nothing ) then
wc.Dispose()
wc = Nothing
end if

end try

end sub


'----------------
'
private sub decode_base64()

dim data_array() as Byte

Trace.Warn( ">", "==============" )
Trace.Warn( ">", "decode_base64:" )

' Attempt to decode from base64 ...
try

data_array = Convert.FromBase64String( m_encoded_data )

Trace.Warn( ">", "data_array.length = " & data_array.length.ToString() )

if ( data_array.length = m_file_size ) then
Trace.Warn( ">", "DECODE OK" )
else
Trace.Warn( ">", "DECODE FAILED!" )
end if

catch ex as Exception
Trace.Warn( ">", ex.ToString() )

end try

end sub
</script>
<html>
<head>
<title>Attempt to encode/decode using Base 64</title>
</head>
<body>
<blockquote>

<form runat="server">
Enter the URL to a file, preferably a small image JPG or GIF file.
<hr noshade size="1">
<table width="90%" border="0" cellpadding="2" cellspacing="1">
<tr>
<td width="20%" align="right" valign="top" class="form_label_1">
URL:
</td>
<td width="80%" align="left" valign="top" class="form_field_1">
<asp:TextBox id="fld_url" text="" size="100" maxlength="200" runat="server" />
</td>
</tr>
</table>
<hr noshade size="1">
<table width="90%" border="0" cellpadding="2" cellspacing="1">
<tr>
<td width="20%"> </td>
<td width="80%" valign="top">
<asp:Button OnClick="do_test" text="Do Base64 Test" runat="server" />
</td>
</tr>
</table>
</form>

</blockquote>
</body>
</html>

Saturday, March 24, 2012

System.Net.Mail.SmtpClient.Send() Error: An invalid character was found in the mail header

hi all!

please help!

I wanted to make an automatic email when I create user by CreateUserWizard. So I configured SMTP, then in properties of the wizard indicated textfile for message and wrote simple subject "registration"

but I have an exception (like in subj).

I even tried to set the subject in event handler for "emailsending" event. Same exception.

What is wrong? How could I fix it?

Here us some info from stack:

[FormatException:An invalid character was found in the mail header.] System.Net.BufferBuilder.Append(String value, Int32 offset, Int32 count) +915954 System.Net.Mail.EHelloCommand.PrepareCommand(SmtpConnection conn, String domain) +106 System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port) +835 System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port) +316 System.Net.Mail.SmtpClient.GetConnection() +42 System.Net.Mail.SmtpClient.Send(MailMessage message) +1485

[SmtpException: Email send failure.] System.Net.Mail.SmtpClient.Send(MailMessage message) +2074 System.Web.UI.WebControls.LoginUtil.SendPasswordMail(String email, String userName, String password, MailDefinition mailDefinition, String defaultSubject, String defaultBody, OnSendingMailDelegate onSendingMailDelegate, OnSendMailErrorDelegate onSendMailErrorDelegate, Control owner) +341 System.Web.UI.WebControls.CreateUserWizard.AttemptCreateUser() +571 System.Web.UI.WebControls.CreateUserWizard.OnNextButtonClick(WizardNavigationEventArgs e) +105 System.Web.UI.WebControls.Wizard.OnBubbleEvent(Object source, EventArgs e) +453 System.Web.UI.WebControls.CreateUserWizard.OnBubbleEvent(Object source, EventArgs e) +149 System.Web.UI.WebControls.WizardChildTable.OnBubbleEvent(Object source, EventArgs args) +17 System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35 System.Web.UI.WebControls.ImageButton.OnCommand(CommandEventArgs e) +115 System.Web.UI.WebControls.ImageButton.RaisePostBackEvent(String eventArgument) +171 System.Web.UI.WebControls.ImageButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +7 System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +11 System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5102

Hi there, can i just ask why you choose me? as for your problem, it looks like there is an invalid character in the mail header, so either there is nothing in it or something there shouldnt be, try taking a few steps back, if your attaching a text file just simply put a few words coded in, and if your header is dynamic try making it hard coded


You were online. Sorry.

It is more simple. There is simpliest string, like "123". Same error


hey no worries, well try a string like abc, also make sure no fields are not left blank. What usually helps me is take a 10 min break, clear you head have a coffee and come back look through your code as if you have never seen it before. something may catch. Im not the worlds best .neter but i usually find if there is a problem its often by taking things back to basic it helps


If your still not having any success you could try the code below and see if it makes any difference.

Regards

Martijn

Sub mailout()Dim mailAsNew Net.Mail.MailMessage()

'set the addresses

mail.To.Add("recipient@.whereever.com")

mail.From =New Net.Mail.MailAddress("sender@.wherever.com"))

'set the content

mail.Subject ="Email Subject line"

mail.Body ="The main body of the email message"

'send the message

Dim smtpAsNew Net.Mail.SmtpClient("smtp.whereever.com")

'to authenticate we set the username and password properites on the SmtpClient

smtp.Credentials =New Net.NetworkCredential("smtp-accountname e.g. sender@.wherever.com","smtp-account-password")

Try

smtp.Send(mail)

response.write("Email sent successfully")

Catch ExAs Exception

response.write("Email send failed error code is... " & Ex.Message)

EndTry

EndSub


no success, same error


I cant come up with any conclusions from your stack trace.

The code I gave you I copied out of an application I wrote there was something I had missed and should have cleaned up in the following line

mail.From =New Net.Mail.MailAddress(Session(sender@.wherever.com))

It should be this (no reference to any session variable)

mail.From =New Net.Mail.MailAddress(sender@.wherever.com)

The only other question is does your recipient or sender email address have any unusual charactors or attempt to have a space in it? Any thing like that could cause a problem. Try the same code with different email addresses and different content.

Sorry no other suggestions

Martijn


May be this piece of code will help:

<system.net>
<mailSettings>
<smtp from="evdokp@.pochta.ru">
<network host="mail.pochta.ru" password="[мой пароль]" userName="evdokp@.pochta.ru" />
</smtp>
</mailSettings>
</system.net>

this is how ASP.NET build-it configuration tool edits web.config

Well, my additional question is: where does the tool sets port value?


ok, my sugesstion is to take remove the brackets from the password and to use a password with standard English character set without and spaces.

Be sure to update the password on the mail server too.

Good luck

<system.net>
<mailSettings>
<smtp from="evdokp@.pochta.ru">
<network host="mail.pochta.ru" password="myPassword" userName="evdokp@.pochta.ru" />
</smtp>
</mailSettings>
</system.net>


it is not that easy.

these brackets are there just because I hide my password. It was like you say "myPassword"

Do you know where port is defined in web.config?