0

I have been trying to post an attachment on a confluence page by following the Confluence Documentation on posting an attachment . I tried the following code to upload an attachment (.txt file or any image file). I also worked with the curl command and it worked for a the confluence installed locally, but gave "certifcates missing" errors while uploading online. The code snippet in C#, on which I am working at the moment is :

string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Credentials = CredentialCache.DefaultCredentials;
req.Headers.Add("X-Atlassian-Token", "nocheck");
req.Method = "POST";
req.ContentType = "multipart/form-data; boundary=" + boundary;
string contentDisp = "Content-Disposition: form-data; name=\"file\"; filename=\"foo.txt\"";
string contentType = "Content-Type: text/plain";
string fullContents = "{0}\r\n{1}\r\n{2}\r\n\r\n{3}\r\n{4}--", boundary, contentDisp,contentType, Encoding.Default.GetString(contents), boundary;
req.ContentLength = fullContents.Length;
using (StreamWriter reqStream = new StreamWriter(req.GetRequestStream()))
{
reqStream.Write(fullContents);
reqStream.Flush();
reqStream.Close();
}
var httpResponse = (HttpWebResponse)req.GetResponse(); 

The error I am getting is : "An unhandled exception of type 'System.Net.WebException' occurred in System.dll. Additional information: The remote server returned an error: (400) Bad Request."

Vinni
  • 23
  • 5
  • Please read [ask] and provide the actual error, and show what your research towards that error yielded. – CodeCaster Sep 05 '16 at 15:34
  • Hey @CodeCaster, thanks for making me realize that the question hasn't been posted properly. I will edit it so as to make it more useful. Thank you. – Vinni Sep 06 '16 at 07:30

1 Answers1

-1

Hopefully this will help

I'm Posting it in VB just in case there are translation issues. You can convert it here:

CodeConverter

Dim nvc As New System.Collections.Specialized.NameValueCollection() 'NOTE: Nothing to send at this time but must be initialized and passed
Dim strTargetUri As String = "https://yourserver.com/rest/api/content/1234567890/child/attachment"
Dim attachmentItem As String = "C:\folder\yourfile.png"
AddImageAttachment(strTargetUri, attachmentItem, "file", "image/jpeg", nvc)

I broke this down into 3 procedures

Public Shared Sub AddImageAttachment(ByVal uri As String, ByVal filePath As Hub.AttachmentElement, ByVal fileParameterName As String, ByVal contentType As String, ByVal otherParameters As Specialized.NameValueCollection)

    ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True

    Dim strFileName As String = filePath.SourceFileName
    Dim strPathAndFileName As String = filePath.SourcePathAndFileName

    Dim boundary As String = "---------------------------" & DateTime.Now.Ticks.ToString("x")
    Dim newLine As String = System.Environment.NewLine
    Dim boundaryBytes As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" & boundary & newLine)
    Dim request As Net.HttpWebRequest = Net.WebRequest.Create(uri)
    'request.Proxy = New WebProxy("127.0.0.1", 8888)    'Proxy Entry for Tracing with Fiddler

    request.ContentType = "multipart/form-data; boundary=" & boundary
    request.Headers.Add("X-Atlassian-Token: no-check")
    request.Headers.Add("Authorization", "Basic " & Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(credLogonID & ":" & credPassword)))
    request.Method = "POST"
    request.Credentials = Net.CredentialCache.DefaultCredentials

    Try

        Using requestStream As Stream = request.GetRequestStream()
            Dim formDataTemplate As String = "Content-Disposition: form-data; name=""{0}""{1}{1}{2}"
            If otherParameters.Keys.Count > 0 Then
                For Each key As String In otherParameters.Keys
                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
                    Dim formItem As String = String.Format(formDataTemplate, key, newLine, otherParameters(key))
                    Dim formItemBytes As Byte() = Text.Encoding.UTF8.GetBytes(formItem)
                    requestStream.Write(formItemBytes, 0, formItemBytes.Length)
                Next key
            End If

            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)

            Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"
            Dim header As String = String.Format(headerTemplate, fileParameterName, strFileName, newLine, contentType)
            Dim headerBytes As Byte() = Text.Encoding.UTF8.GetBytes(header)
            requestStream.Write(headerBytes, 0, headerBytes.Length)

            Dim byteImage As Byte() = GetImage(strPathAndFileName)

            requestStream.Write(byteImage, 0, byteImage.Length)

            Dim trailer As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" + boundary + "--" & newLine)
            requestStream.Write(trailer, 0, trailer.Length)
        End Using

        Dim response As WebResponse = Nothing

    Catch e As Net.WebException
        MsgBox(e.Message)
    End Try
End Sub

GetImage

Private Shared Function GetImage(ByVal URL As String) As Byte()

    GetImage = Nothing

    ServicePointManager.ServerCertificateValidationCallback = Function(sender, certificate, chain, sslPolicyErrors) True
    Dim Request As HttpWebRequest = Nothing
    Dim Response As HttpWebResponse = Nothing
    Try
        Request = WebRequest.Create(URL)
        'request.Proxy = New WebProxy("127.0.0.1", 8888)    'Proxy Entry for Tracing with Fiddler
        Request.Credentials = CredentialCache.DefaultCredentials
        Response = CType(Request.GetResponse, WebResponse)
        If Request.HaveResponse Then
            If Response.StatusCode = Net.HttpStatusCode.OK Then
                GetImage = convertStreamToByte(Response.GetResponseStream)
            End If
        End If
    Catch e As WebException
        MsgBox(e.Message)
    End Try

    Return GetImage

End Function

and the byte converter

Private Shared Function convertStreamToByte(ByRef incomingStream As Stream) As Byte()

    Dim result As Byte()
    Dim buffer As Byte() = New Byte(4095) {}
    Using memoryStream As New MemoryStream()
        Dim count As Integer = 0
        Do
            count = incomingStream.Read(buffer, 0, buffer.Length)
            memoryStream.Write(buffer, 0, count)
        Loop While count <> 0
        result = memoryStream.ToArray()
    End Using
    Return result

End Function

I'll see if I can find some of the links I used to bring this together

mreinsmith
  • 124
  • 1
  • 14
  • Stack Overflow is not a "share your favorite snippet to do X" site. This cobbled together piece of code (for example [from here](http://stackoverflow.com/questions/4388689/)) introduces [Cargo cult programming](https://en.wikipedia.org/wiki/Cargo_cult_programming) and does not answer the OP's question, which is _"Why doesn't this code work?"_, the latter being unanswerable in the first place because from the question it's lacking why exactly it doesn't work. So while I do applaud your effort to help the OP, in fact I'm afraid you aren't helping per se. – CodeCaster Sep 05 '16 at 15:39
  • I went through this same issue myself and learned that the available knowledge doesn't address the full scope of the problem. I believe that Vinnie is at that same point. I wanted to show him and anyone else experiencing this issue that the answer required several steps. Again, because I've been there myself – mreinsmith Sep 05 '16 at 15:51
  • This is not the only, let alone the cleanest way to upload files as part of a multipart/form-data request. See for example [How to upload file to server with HTTP POST multipart/form-data](http://stackoverflow.com/questions/19954287/how-to-upload-file-to-server-with-http-post-multipart-form-data). If you wanted to teach the OP and later visitors something, then you should document what this code actually does and which assumptions it makes, instead of dumping code as "use this, it'll solve your problem". – CodeCaster Sep 05 '16 at 15:52
  • I wish I had the time, enjoy your holiday – mreinsmith Sep 05 '16 at 15:56
  • Hey @mreinsmith thank you!! You code worked perfectly! Although I did some modifications : in GetImage, I used System.Net.FileWebRequest instead of HttpWebRequest and System.Net.WebResponse in place of HttpWebResponse. Rest everything worked fine. Thank you so much for you help. :) – Vinni Sep 06 '16 at 10:03
  • @CodeCaster I understood the code that mreinsmith posted, I am sure others, in the same situation as mine, will understand it too. Your links were not so useful, but thanks for your suggestions anyway. :) – Vinni Sep 06 '16 at 10:05
  • That's great! The filewebrequest is a great idea, think I'll update that in mine. Confluence is fun isn't it :-) – mreinsmith Sep 06 '16 at 10:11
  • Yes it totally is! ;) – Vinni Sep 06 '16 at 11:28