Многострадальный вопрос, на который нигде не могу внятно ответить. Вот простой код, которым я пытаюсь отправить файла на сервер Code: // tsend.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <wininet.h> #include <tchar.h> #include <iostream> #pragma comment(lib,"wininet.lib") using namespace std; int _tmain(int argc, _TCHAR* argv[]) { static TCHAR frmdata[] = _T("-----------------------------7d82751e2bc0858\r\nContent-Disposition: form-data; name=\"file\"; filename=\"C:\\test.txt\"\r\nContent-Type: text/plain\r\n\r\nAAAAAAAAAAAAAAAAA\r\n-----------------------------7d82751e2bc0858--\r\n"); static TCHAR hdrs[] = L"Content-Type: multipart/form-data; boundary=---------------------------7d82751e2bc0858"; HINTERNET hSession = InternetOpen(L"MyAgent",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if(hSession==NULL) { cout<<"Error: InternetOpen"; system("PAUSE"); } HINTERNET hConnect = InternetConnect(hSession, L"127.0.0.1",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); if(hConnect==NULL) { cout<<"Error: InternetConnect"; system("PAUSE"); } HINTERNET hRequest = HttpOpenRequest(hConnect, L"POST",L"/upload/upload.php", NULL, NULL, NULL, 0, 1); if(hRequest==NULL) { cout<<"Error: HttpOpenRequest"; system("PAUSE"); } BOOL sent= HttpSendRequest(hRequest, hdrs, wcslen(hdrs), frmdata, wcslen(frmdata)*sizeof(TCHAR)); if(!sent) { cout<<"Error: HttpSendRequest"; system("PAUSE"); } //close any valid internet-handles InternetCloseHandle(hSession); InternetCloseHandle(hConnect); InternetCloseHandle(hRequest); } /* static TCHAR frmdata[] = L"-----------------------------7d82751e2bc0858\r\nContent-Disposition: form-data; name=\"file\"; filename=\"C:\\test.txt\"\r\nContent-Type: text/plain\r\n\r\nAAAAAAAAAAAAAAAAA\r\n-----------------------------7d82751e2bc0858--\r\n"; static TCHAR hdrs[] = L"Content-Type: multipart/form-data; boundary=---------------------------7d82751e2bc0858"; HINTERNET hSession = InternetOpen(L"MyAgent",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if(hSession==NULL) { cout<<"Error: InternetOpen"; } HINTERNET hConnect = InternetConnect(hSession, L"127.0.0.1",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); if(hConnect==NULL) { cout<<"Error: InternetConnect"; } HINTERNET hRequest = HttpOpenRequest(hConnect, L"POST",L"/upload/upload.php", NULL, NULL, NULL, 0, 1); if(hRequest==NULL) { cout<<"Error: HttpOpenRequest"; } BOOL sent= HttpSendRequest(hRequest, hdrs, wcslen(hdrs), frmdata, wcslen(frmdata)*sizeof(TCHAR)); if(!sent) { cout<<"Error: HttpSendRequest"; */ Вот в каком виде приходят данные: Code: listening on [any] 80 ... connect to [127.0.0.1] from validation.sls.microsoft.com [127.0.0.1] 49280 POST /upload/upload.php HTTP/1.1 Content-Type: multipart/form-data; boundary=---------------------------7d82751e2 bc0858 User-Agent: MyAgent Host: 127.0.0.1 Content-Length: 420 Cache-Control: no-cache Cookie: s_pers=%20s_fid%3D6D463DCA024AF939-1C2604BDB2B68135%7C1457266833122%3B%2 0s_vs%3D1%7C1394110233124%3B%20s_nr%3D1394108433125-Repeat%7C1425644433125%3B - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7 d 8 2 7 5 1 e 2 b c 8 5 8 C o n t e n t - D i s p o s i t i o n : f o r m - d a t a ; n a m e = " f i l e " ; f i l e n a m e = " C : \ t e s t . t x t " C o n t e n t - T y p e : t e x t / p l a i n A A A A A A A A A A A A A A A A A - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 7 d 8 2 7 5 1 e 2 b c 0 8 5 8 - - Между символами пробелы и сервер файл не воспринимает и не загружает. Я так понял что это из-за того, что данные в TCHAR. Потому что в чаре они отправляются нормально. Так вот вопрос. Как же быть? Во-первых потому что у меня везде tchar в проекте, а во-вторых, если я буду бинарь отправлять, то данные будут выглядеть так 1. данные в tchar 2. тело файла в byte 3. завершение (данные в tchar) И получается ерунда. Что в таких случаях делать и как солиднее поступить? Спасибо всем ответившим.
Это не пробелы, а нули. У тебя используется UNICODE, отсюда все проблемы. Чем вообще обусловленно использование TCHAR, вместо ANSI char
Насколько я знаю, TCHAR предпочтительнее использовать, потому что этот макрос сам меняет размер char в зависимости от того, установлен UNICODE или нет. В любом случае, у меня вопрос именно в том - почему так происходит и как с этим бороться. Или данные в wide char нельзя вообще посылать? Я этот момент не пойму. И почему там нули. Хедер вроде тоже tchar но в неткате нормально отображазился. Может какие-то еще манипуляции нужно провернуть?
Code: void http_upload_file(PCHAR szServer, PCHAR szScript, PCHAR szParam, PCHAR szValue, PCHAR szFile) { PCHAR szHeaders = "Content-Type: multipart/form-data; boundary=----qwerty"; PCHAR szData = "------qwerty\r\n" "Content-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n" "------qwerty\r\n" "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n" "Content-Type: application/octet-stream\r\n" "Content-Transfer-Encoding: binary\r\n\r\n"; PCHAR szDataEnd = "\r\n------qwerty--\r\n"; char szHeader[512]; HINTERNET hSession, hConnect, hRequest; DWORD dwFileSize, dwBytesRead, dwContentLength; hSession = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (hSession) { hConnect = InternetConnect(hSession, szServer, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (hConnect) { hRequest = HttpOpenRequest(hConnect, "POST", szScript, NULL, NULL, 0, 0, 0); if (hRequest) { HANDLE hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); if (hFile != INVALID_HANDLE_VALUE) { dwFileSize = GetFileSize(hFile, NULL); wsprintf(szHeader, szData, szParam, szValue, szFile); dwContentLength = lstrlen(szHeader) + dwFileSize + lstrlen(szDataEnd); LPBYTE pBuf = (LPBYTE)malloc(dwContentLength); CopyMemory(&pBuf[0], szHeader, lstrlen(szHeader)); ReadFile(hFile, &pBuf[lstrlen(szHeader)], dwFileSize, &dwBytesRead, NULL); CopyMemory(&pBuf[lstrlen(szHeader) + dwFileSize], szDataEnd, lstrlen(szDataEnd)); HttpSendRequest(hRequest, szHeaders, lstrlen(szHeaders), pBuf, dwContentLength); CloseHandle(hFile); free(pBuf); } } InternetCloseHandle(hRequest); } InternetCloseHandle(hConnect); } InternetCloseHandle(hSession); } //http_upload_file php: move_uploaded_file($_FILES["file"]["tmp_name"], $file);
Лол, я только что хотел тебе на васме написать. Но у тебя тут чар везде. Я пробовал оставить ту часть тела запроса, где у тебя szData - в char, но туда потом имя файла нужно впрыскивать, а у меня в проекте все TCHAR и опять облом. Мне интересно именно с TCHAR что делать . Как-то же люди такие проекты делают.
>> Мне интересно именно с TCHAR что делать - если в файле встретится нулевой байт, это будет означать конец TCHAR. С TCHAR можно будет отправлять только текстовые файлы(не бинарные)
Code: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Local variables static char *filename = "test.txt"; //Filename to be loaded static char *type = "text/plain"; static char boundary[] = "boundary123"; //Header boundary static char iaddr[] = "сервер"; //IP address static char url[] = "/upload.php"; //URL char hdrs[255]; //Headers char * buffer; //Buffer containing file + headers char * content; //Buffer containing file FILE * pFile; //File pointer long lSize; //File size size_t result; // Open file pFile = fopen ( filename , "rb" ); if (pFile==NULL) ShowMessage("ERROR_OPEN_FILE"); // obtain file size: fseek (pFile , 0 , SEEK_END); lSize = ftell (pFile); rewind (pFile); // allocate memory to contain the whole file: content = (char*) malloc (sizeof(char)*lSize + 1); if (content == NULL) ShowMessage("ERROR_MEMORY"); content[lSize] = '\0'; // copy the file into the buffer: result = fread (content,1,lSize,pFile); if (result != lSize) ShowMessage("ERROR_SIZE"); // terminate fclose (pFile); //allocate memory to contain the whole file + HEADER buffer = (char*) malloc (sizeof(char)*lSize + 2048); //print header sprintf(hdrs,"Content-Type: multipart/form-data; boundary=%s",boundary); sprintf(buffer,"--%s\r\nContent-Disposition: form-data; name=\"%s\"; data=\"%s\"\r\n",boundary,"12345.txt","12345.txt"); sprintf(buffer,"%sContent-Type: %s\r\n\r\n",buffer,type); sprintf(buffer,"%s%s\r\n",buffer,content); sprintf(buffer,"%s--%s--\r\n",buffer,boundary); //Open internet connection HINTERNET hSession = InternetOpen("WinSock",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if(hSession==NULL) ShowMessage("ERROR_INTERNET_OPEN"); HINTERNET hConnect = InternetConnect(hSession, iaddr,INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); if(hConnect==NULL) ShowMessage("ERROR_INTERNET_CONN"); HINTERNET hRequest = HttpOpenRequest(hConnect, (const char*)"POST",url, NULL, NULL, (const char**)"*/*\0", 0, 1); if(hRequest==NULL) ShowMessage("ERROR_INTERNET_REQ"); BOOL sent= HttpSendRequest(hRequest, hdrs, strlen(hdrs), buffer, strlen(buffer)); if(!sent) ShowMessage("ERROR_INTERNET_SEND"); char buf[1000]; DWORD nRead; InternetReadFile(hRequest, buf, 1000, &nRead); buf[nRead] = '\0'; //close any valid internet-handles InternetCloseHandle(hSession); InternetCloseHandle(hConnect); InternetCloseHandle(hRequest); return 0; }
Предыдущая с PCHAR, может пригодится, реализация с base 64: Code: char *Base64Encode(const BYTE *data, DWORD dwLenth) { char *lpData; DWORD dwLen = 0; if (CryptBinaryToStringA(data, dwLenth, CRYPT_STRING_BASE64, NULL, &dwLen)) { dwLen++; lpData = new CHAR[dwLen]; if (CryptBinaryToStringA(data, dwLenth, CRYPT_STRING_BASE64, lpData, &dwLen)) return lpData; } return NULL; } char *Base64Encode(const char *s) { char *lpData; DWORD dwLen = 0; DWORD sLen = lstrlenA(s); if (CryptBinaryToStringA((BYTE*)s, sLen, CRYPT_STRING_BASE64, NULL, &dwLen)) { lpData = new CHAR[dwLen]; if (CryptBinaryToStringA((BYTE*)s, sLen, CRYPT_STRING_BASE64, lpData, &dwLen)) return lpData; } return NULL; } char *Base64Decode(const char *s) { BYTE *pbData; DWORD dwLen = 0; DWORD sLen = lstrlenA(s); if (CryptStringToBinaryA(s, sLen, CRYPT_STRING_BASE64, NULL, &dwLen, NULL, NULL)) { pbData = new BYTE[dwLen + 1]; if (CryptStringToBinaryA(s, sLen, CRYPT_STRING_BASE64, pbData, &dwLen, NULL, NULL)) { pbData[dwLen] = 0; return (char *)pbData; } } return NULL; } void SendPostRequest(char *host, char *gate, char *FileName) { HINTERNET hSession = InternetOpen(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hSession != NULL) { HINTERNET hConnect = InternetConnect(hSession, host, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL); if (hConnect != NULL) { HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", gate, NULL, NULL, NULL, NULL, NULL); if (hRequest != NULL) { DWORD dwRetSize, dwFileSize; BYTE *pSendData; HANDLE hFile = CreateFile(FileName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) { dwFileSize = GetFileSize(hFile, 0); pSendData = (BYTE *)VirtualAlloc(0, dwFileSize, MEM_COMMIT, PAGE_READWRITE); ReadFile(hFile, pSendData, dwFileSize, &dwRetSize, 0); } CloseHandle(hFile); char *post_data; post_data = Base64Encode(pSendData, dwFileSize); VirtualFree(pSendData, 0, MEM_RELEASE); char *buf; buf = (char *)VirtualAlloc(0, strlen(post_data) + 5, MEM_COMMIT, PAGE_READWRITE); strcpy(buf, "data="); strcat(buf, post_data); char *headers = "Content-Type: application/x-www-form-urlencoded"; HttpSendRequest(hRequest, headers, strlen(headers), buf, strlen(buf)); VirtualFree(buf, 0, MEM_RELEASE); delete [] post_data; } InternetCloseHandle(hRequest); } InternetCloseHandle(hConnect); } InternetCloseHandle(hSession); } void main() { SendPostRequest("localhost", "index.php", "1.exe"); system("PAUSE"); }
Спасибо за сорцы, но то есть никакого решения нет? Нужно все под чар переписывать и юникод не использовать? Мне все-таки интересно, если ли какое-нибудь решение для юникода.
>>Мне все-таки интересно, если ли какое-нибудь решение для юникода. - во втором по счету исходнике нужно сменить тип переменно на юникод и добавить W к используемым функциям, попробуй, должно работать.
Изначально сложный подход. Написал прогу для обхода банов на одной соц-сети, строго на 256-битной кодировке пассов. Начал переписывать под юникод, учитывая особенности той соц-сети и дело встало. Универсального решения нет - нужно смотреть, какая кодировка используется на сайте/клиенте, для которой и кодируется прога. Идея технически верная программы, но не обязательно, что будет работать на всех сайтах.
Так, перечитал ваши сообщения и одновременно советы с других форумов, повозился с кодом и методом научного тыка вроде написал работающий вариант. Если кому пригодится, то вот сорец: Code: #include <windows.h> #include <sstream> #include <shellapi.h> #include <wininet.h> #pragma comment(lib, "wininet") int SendHttpFile(TCHAR *szFileName); int _tmain(int argc, _TCHAR* argv[]) { SendHttpFile(L"C:\\Windows\\Temp\\hi.exe"); } int SendHttpFile(TCHAR *szFileName) { TCHAR szHost[] = L"127.0.0.1"; TCHAR szURL[] = L"/upload/upload.php"; TCHAR szUserAgent[] = L"Opera!"; TCHAR szFrmdata_0[] = L"-----------------------------7d82751e2bc0858\r\nContent-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n"; TCHAR szFrmdata_2[] = L"\r\n-----------------------------7d82751e2bc0858--\r\n"; TCHAR szHdrs[] = L"Content-Type: multipart/form-data; boundary=---------------------------7d82751e2bc0858"; TCHAR *szFrmdata_1; char *szBodyBegin, *szBodyEnd; char *szForm; BOOL IsSent; HANDLE hFile; DWORD dwFileSize = 0, dwContentLength, dwRwBytes, dwLastError, dwLenFrmdata_1, dwLenBodyBegin, dwLenBodyEnd, dwLenForm; BYTE *ReadBuffer; std::stringstream ssErr; hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!hFile) { dwLastError = GetLastError(); MessageBoxA(NULL, (LPCSTR)L"Error", (LPCSTR)"Error", MB_OK); return 0; } dwFileSize = GetFileSize(hFile, &dwFileSize); ReadBuffer = (BYTE*) malloc(dwFileSize); if(!ReadFile(hFile, ReadBuffer, dwFileSize, &dwRwBytes, NULL)) return 0; CloseHandle(hFile); //SendFile dwLenFrmdata_1 = wcslen(szFrmdata_0)*sizeof(TCHAR) + wcslen(szFileName) *sizeof(TCHAR); szFrmdata_1 = (TCHAR *)malloc(dwLenFrmdata_1); wsprintf(szFrmdata_1, szFrmdata_0, szFileName); dwLenBodyBegin = wcslen(szFrmdata_1)*sizeof(TCHAR); dwLenBodyEnd = wcslen(szFrmdata_2)*sizeof(TCHAR); szBodyBegin = (char *)malloc(dwLenBodyBegin); szBodyEnd = (char *)malloc(dwLenBodyEnd); ZeroMemory(szBodyBegin, dwLenBodyBegin); ZeroMemory(szBodyEnd, dwLenBodyEnd); WideCharToMultiByte(CP_ACP, 0, szFrmdata_1, -1, szBodyBegin, dwLenBodyBegin, 0, 0); WideCharToMultiByte(CP_ACP, 0, szFrmdata_2, -1, szBodyEnd, dwLenBodyEnd, 0, 0); dwLenForm = strlen(szBodyBegin) + strlen(szBodyEnd) + dwFileSize; szForm = (char *)malloc(dwLenForm); ZeroMemory(szForm, dwLenForm); memcpy(szForm + (strlen(szBodyBegin)), ReadBuffer, dwFileSize); memcpy(szForm, szBodyBegin, strlen(szBodyBegin)); memcpy(szForm + dwFileSize+(strlen(szBodyBegin)), szBodyEnd , strlen(szBodyEnd)); HINTERNET hSession = InternetOpen(szUserAgent,INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hSession) { /* dwLastError = GetLastError(); ssErr << dwLastError; std::string strErr = ssErr.str(); LPCSTR CstrErr = strErr.c_str(); MessageBoxA(NULL, (LPCSTR)"InternetOpen Error", CstrErr, MB_OK); */ return 0; } HINTERNET hConnect = InternetConnect(hSession, szHost, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1); if (!hConnect) { /* dwLastError = GetLastError(); ssErr << dwLastError; std::string strErr = ssErr.str(); LPCSTR CstrErr = strErr.c_str(); MessageBoxA(NULL, (LPCSTR)"InternetConnect Error", CstrErr, MB_OK); */ return 0; } HINTERNET hRequest; hRequest = HttpOpenRequest(hConnect, L"POST", szURL, NULL, NULL, NULL , INTERNET_FLAG_RELOAD, 0); if (!hRequest) { /* dwLastError = GetLastError(); ssErr << dwLastError; std::string strErr = ssErr.str(); LPCSTR CstrErr = strErr.c_str(); MessageBoxA(NULL, (LPCSTR)"HttpOpenRequest Error", CstrErr, MB_OK); */ return 0; } //dwLastError = GetLastError(); IsSent = HttpSendRequest(hRequest, szHdrs, wcslen(szHdrs), szForm, dwLenForm); if (!IsSent) { /* dwLastError = GetLastError(); ssErr << dwLastError; std::string strErr = ssErr.str(); LPCSTR CstrErr = strErr.c_str(); MessageBoxA(NULL, (LPCSTR)"HttpSendRequest Error", CstrErr, MB_OK); */ return 0; } InternetCloseHandle(hSession); InternetCloseHandle(hConnect); InternetCloseHandle(hRequest); return 1; } Еще раз всем спасибо!
WideCharToMultiByte, MultiByteToWideChar, В функциях типа sprintf, wsprintf присутствуют шаблоны типа %s - %S например из ANSI в UNICODE wsprintf(wchar, "%S", char); Некоторые API функции имеют A,W буквы в конце... надо тебе char достать из edit control GetWindowTextA надо wchar GetWindowTextW Функций преобразования куча. И тебе никто не запрещает внутри программы нужные HTTP запросы хранить в ANSI (char).