gpx Upload with MFC

Hi all,

I want to upload a recorded gpx log direct from my PPC with an MFC based application, but I’d never handled http POSTs before.
Now I set up a function and tested successful it with a test php on my server but it fails on OSM because I don’t know how I have to handle the user (email), password.
The server returns StatusCode 200 (no error) but the html page reports
Upload GPS Trace
1 error prohibited this trace from being saved

There were problems with the following fields:

  • User can’t be blank

Can somebody help me? Here is the code:

BOOL SendTrack(CString csUser, CString csPassWD, CString csFileName, CString csTags, CString csDescription, BOOL bPublic)
{
    CString strFullPath = _T("http://www.openstreetmap.org/trace/create");

    //Just dummy data. This will be replaced by content of the csFileName file
    CString csTestData =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
    <gpx version=\"1.0\" creator=\"Glopus - http://www.glopus.de\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
        xmlns=\"http://www.topografix.com/GPX/1/0\" \
        xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\"> \
        <time>2007-11-06T20:27:50Z</time> \
    <bounds minlat=\"48.000\" minlon=\"11.000\" maxlat=\"48.100\" maxlon=\"11.1000\"/> \
    <trk> \
    <trkseg>\
    <trkpt lat=\"48.05\" lon=\"11.05\">\
    <time>2004-09-22T04:18:27Z</time>\
    <course>108.550003</course>\
    <speed>0.027221</speed>\
    </trkpt>\
    </trkseg>\
    </trk>\
</gpx>";


    BOOL bSuccess = TRUE;

    CInternetSession session(NULL, 0, PRE_CONFIG_INTERNET_ACCESS);
    CHttpConnection * pServer = NULL;
    CHttpFile * pFile = NULL;

    CString strServerName;
    CString strObject;
    INTERNET_PORT nPort;
    DWORD dwServiceType;
    CHttpFile *pHTTP = 0;
    TCHAR szError[MAX_PATH];

    if (!AfxParseURL(strFullPath, dwServiceType, strServerName, strObject, nPort) || 
            dwServiceType != INTERNET_SERVICE_HTTP)
        return FALSE;
    session.EnableStatusCallback(TRUE);

    pServer = session.GetHttpConnection(strServerName, nPort, csUser, csPassWD);


    try
    {
        CString csPreFileData, csPostFileData, csHeader, csBoundary = "xyzw";
        // I tried to send the Authorization here, but no success
        /*
                                CBase64 Encoder;
        CString UserPW = csUser + _T(":") + csPassWD;
        UserPW = Encoder.Encode(UserPW, UserPW.GetLength());

        csHeader += _T("Authorization: Basic ") + UserPW + _T("\r\n"); 
                                */
        csHeader += _T("Content-Type: multipart/form-data; boundary=") + csBoundary + _T("\r\n");

        // also this was not accepted        /*
         csPreFileData += _T("--") + csBoundary;
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Disposition: form-data; name=\"trace[user]\"");
        csPreFileData += _T("\r\n\r\n");
        csPreFileData += csUser;
        csPreFileData += _T("\r\n");
                                */
        
        csPreFileData += _T("--") + csBoundary;
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Disposition: form-data; name=\"trace[public]\"");
        csPreFileData += _T("\r\n\r\n");
        csPreFileData += bPublic?_T("1"):_T("0");
        csPreFileData += _T("\r\n");
        
        csPreFileData += _T("--") + csBoundary;
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Disposition: form-data; name=\"trace[description]\"");
        csPreFileData += _T("\r\n\r\n");
        csPreFileData += csDescription;
        csPreFileData += _T("\r\n");
        
        csPreFileData += _T("--") + csBoundary;
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Disposition: form-data; name=\"trace[tagstring]\"");
        csPreFileData += _T("\r\n\r\n");
        csPreFileData += csTags;
        csPreFileData += _T("\r\n");
        
        csPreFileData += _T("--") + csBoundary;
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Disposition: form-data; name=\"trace[gpx_file]\"; filename=\"") + csFileName + "\"";
        csPreFileData += _T("\r\n");
        csPreFileData += _T("Content-Type: text/xml");
        csPreFileData += _T("\r\n\r\n");
        
        csPostFileData = _T("\r\n");
        csPostFileData += _T("--") + csBoundary + _T("--");
        csPostFileData += _T("\r\n");
        
        
        DWORD dwSize = (DWORD)csPreFileData.GetLength() + (DWORD)csPostFileData.GetLength() + (DWORD)csTestData.GetLength();

        pHTTP = pServer->OpenRequest(CHttpConnection::HTTP_VERB_POST, strObject, NULL,1,NULL,"HTTP/1.0",INTERNET_FLAG_RELOAD); 
        
        pHTTP->AddRequestHeaders(csHeader);
        
        pHTTP->SendRequestEx(dwSize, HSR_SYNC | HSR_INITIATE);

#ifdef _UNICODE
        pHTTP->Write(W2A(csPreFileData), csPreFileData.GetLength());
        pHTTP->Write(W2A(csTestData), csTestData.GetLength());
        pHTTP->Write(W2A(csPostFileData), csPostFileData.GetLength());
#else
        pHTTP->Write((LPSTR)(LPCSTR)csPreFileData, csPreFileData.GetLength());
        pHTTP->Write((LPSTR)(LPCSTR)csTestData, csTestData.GetLength());
        pHTTP->Write((LPSTR)(LPCSTR)csPostFileData, csPostFileData.GetLength());
#endif

        pHTTP->EndRequest(HSR_SYNC);

        DWORD dwRet;
        pHTTP->QueryInfoStatusCode(dwRet);
        if (dwRet != 200)
            throw;


        CString csResponse;
        dwSize = (DWORD)pHTTP->GetLength();
        while (0 != dwSize)
        {
            char *szResponse = (LPSTR)malloc(dwSize + 1);
            szResponse[dwSize] = '\0';
            pHTTP->Read(szResponse, dwSize);
            csResponse += CString(szResponse);
            free(szResponse);
            dwSize = (DWORD)pHTTP->GetLength();
        }

        AfxMessageBox(csResponse);

    }

    catch (CException* e)
    {
        e->GetErrorMessage(szError, MAX_PATH);
        e->Delete();
        AfxMessageBox(szError);
        bSuccess = FALSE;
    }

    pHTTP->Close();
    delete pHTTP;

    if ( pServer != NULL )
    {
        pServer->Close();
        delete pServer;
    }
    session.Close();

    return bSuccess;

}

Thanks,
Peter

I assume you’ve found the 0.5 API documentation and HTTP protocol description in the wiki?

The first yes, but the second is new. I’ll try it, thanks.

:frowning:
Doesn’t work anyway. The PUT request sample describes a diffent target: Create a node. But I want to upload a gpx. Beside this it describes the old 0.4 protocol. Additional hints?

Nope, I haven’t programmed against the API yet. Can you not combine the info in both pages, imho this should be possible.

Trying something else, do you know you can use JOSM for uploading GPX files? Maybe that can solve your problem…

I tried a lot of combinations but I’m a beginner in such HTTP talk and this is probably the reason. :confused: I can upload GPX with other tools. And probably I have no problems if I use Perl or the libs described here http://wiki.openstreetmap.org/index.php/Batch_Upload But this is not possible for my project.

The URL I tried because it is used by the web interface. But of cause I also tried “http://www.openstreetmap.org/api/0.5/gpx/create”, but it doesn’t help. Only the response is different: Error 500.
Unfortunately the put request descibed here http://wiki.openstreetmap.org/index.php/HTTP_Protocol_Specification is different. It just sends a header with Authorization and the data is the xml with the node info.
For gpx I have to submit additiona parameters like trace[gpx_file] and trace[public].
It would help to istall a sniffer and collect the traffic e.g. from JOSM but I never did such things and I wont destroy my system.

JOSM doesn’t yet deal with GPX uploads afaik, there are plans to implement it soon.

It may be worthwhile contacting the dev@ mailing list for support with this api method, I don’t think that it is extensively used yet.

Hi Peter, Thomas,

I would like to do the same. I’m one of the developers of Run.GPS, a Pocket PC and Smartphone based software for sports and outdoor activities. Our users would like to upload their tracks directly to OpenStreetMap.org (e.g. http://www.gps-sport.net/forums/thread/206-0/OpenStreetMap) and I think that would make sense.

In Run.GPS there is a “synchronize tracks” function so you could easily upload all new tracks with one click.

As said on this page:
http://wiki.openstreetmap.org/index.php/Batch_Upload
one would have to upload to http://www.openstreetmap.org/api/0.5/gpx/create and provide basic authentication information (base64 encoded).

@Peter: did you get it working, finally? I think your code looks alright.

Cheers

Tom

There was a problem with the GPX upload method but TomH has fixed it.