// httpget - simply wget clone // // Author: Tomasz Maciejewski (ponton at jabster.pl) // License: GPLv3 (http://www.gnu.org/licenses/gpl-3.0.html) #include #include #include #include #include #include #include #include #include #include #include using namespace std; void podmien(string &, const regex_t &, const string &); struct Naglowki { unsigned code; // kod odpowiedzi string wszystkie; // naglowki "surowe" string mime; // mime string enc; // transfer-encoding unsigned len; // content-length }; struct OdpowiedzSerwera { Naglowki naglowki; // naglowki vector odp; // bufor odpowiedzi }; // laczy z serwerem i zwraca deskryptor gniazda int polacz(const char *host) { typedef struct sockaddr SA; sockaddr_in adres_serwera; memset(&adres_serwera, 0, sizeof(adres_serwera)); adres_serwera.sin_family = AF_INET; adres_serwera.sin_port = htons(80); hostent *hent; cout << "Znajdowanie hosta " << host << "... " << flush; hent = gethostbyname(host); if (hent == NULL) { throw string("Nie mozna znalezc serwera"); return 0; } cout << "Znaleziono" << endl; memcpy(&adres_serwera.sin_addr, hent->h_addr_list[0], hent->h_length); int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == 0) { throw string("Nie mozna utworzyc gniazda"); } cout << "Laczenie... " << flush; if (connect (sock, (SA*) &adres_serwera, sizeof(adres_serwera)) != 0) { throw string("Nie udalo sie polaczyc z serwerem"); } cout << "Polaczono" << endl; return sock; } // wysyla odpowiednie naglowki void wyslij_naglowki(int sock, string host, string request) { string headers; headers = "GET " + request + " HTTP/1.1\n"; headers += "Host: " + host + "\n"; headers += "Accept-Encoding: identity: q=1.0;\n"; headers += "User-Agent: httpget/1.0\n"; headers += "\n"; // cout << "Wyslane naglowki:\n" << headers << endl; write(sock, headers.c_str(), headers.length()); } // uzupelnia pozostale pola w Naglowki void parsuj_naglowki(Naglowki &n) { istringstream str(n.wszystkie); string nazwa, wartosc; while (str.good()) { str >> nazwa; getline(str, wartosc); istringstream swartosc(wartosc); if (nazwa == "HTTP/1.1" || nazwa == "HTTP/1.0") { swartosc >> n.code; } if (nazwa == "Content-Type:") { swartosc >> n.mime; } else if (nazwa == "Content-Length:") { swartosc >> n.len; } else if (nazwa == "Transfer-Encoding:") { swartosc >> n.enc; } } } // odbiera odpowiedz serwera OdpowiedzSerwera odbierz_odpowiedz(int sock) { OdpowiedzSerwera o; char buf[2048]; string naglowki; int len, downloaded=0; vector::iterator koniec_nagl; bool odebrane_naglowki=false; char separator[] = "\r\n\r\n"; // separator naglowkow i odpowiedzi o.naglowki.enc = "identity"; // domyslna wartosc while ((len = read(sock, buf, 2047)) > 0) { buf[len] = '\0'; // dodaj do wektora o.odp.insert(o.odp.end(), buf, buf+len); // czy pobralismy naglowki? if (odebrane_naglowki == false) { // jesli juz sa cale if ((koniec_nagl = search(o.odp.begin(), o.odp.end(), separator, separator + 4)) != o.odp.end() ) { odebrane_naglowki = true; o.naglowki.wszystkie.assign(o.odp.begin(), koniec_nagl); o.odp.erase(o.odp.begin(), koniec_nagl+4); parsuj_naglowki(o.naglowki); } } downloaded += len; cout << "\rSciagnieto: " << downloaded << " bajtow" << flush; // jesli juz wszystko sciagnieto if (odebrane_naglowki) if (o.odp.size() == o.naglowki.len) { break; } } cout << endl; if (o.naglowki.enc == "chunked") { vector::iterator it; int i, ile_bajtow = 0; it = o.odp.begin(); while (it != o.odp.end()) { string tmp; while (*it != '\n') { tmp += *it; o.odp.erase(it); } o.odp.erase(it); istringstream(tmp) >> hex >> ile_bajtow; // cout << "ile_bajtow = " << ile_bajtow << endl; i = ile_bajtow; while (i > 0) { // cout << i << " -> " << *it << endl; ++it; --i; } o.odp.erase(it); o.odp.erase(it); if (ile_bajtow == 0) break; } } return o; } // sciaga plik i zwraca nazwe pliku, gdzie sciagnal string sciagnij_plik(string s, bool zamien_obrazki = false) { string host, request, filename; // usun "http://" if (s.substr(0, 7) == "http://") s = s.erase(0, 7); size_t i = s.find_first_of('/'); if (i == string::npos) { // nie ma '/' host = s; request = "/"; } else { host = s.substr(0, i); request = s.substr(i); } if (request == "/") filename = "index.html"; else { filename = request.substr(0, request.find_first_of("?")); filename = filename.substr(filename.find_last_of("/")+1); } // cout << "Filename: " << filename << endl; int sock = polacz(host.c_str()); wyslij_naglowki(sock, host, request); OdpowiedzSerwera o = odbierz_odpowiedz(sock); close(sock); cout << "Kod odpowiedzi: " << o.naglowki.code << endl; // cout << "Naglowki:\n" << o.naglowki.wszystkie << endl; ofstream plik(filename.c_str()); if (zamien_obrazki == true) { regex_t r_img, r_css; string strona(o.odp.begin(), o.odp.end()); string baza = host + request.substr(0, request.find_last_of('/')) + '/'; regcomp(&r_img,"]\\+src=\"\\([^\"]*\\)\"", REG_ICASE); regcomp(&r_css,"]\\+rel=\"stylesheet\" href=\"\\([^\"]*\\)\"", REG_ICASE); podmien(strona, r_img, baza); podmien(strona, r_css, baza); regfree(&r_img); regfree(&r_css); plik << strona; } else { vector::iterator it; for (it = o.odp.begin(); it != o.odp.end(); ++it) { plik << *it; } } plik.close(); cout << "Zapisano do pliku " << filename << endl; return filename; } void podmien(string & strona, const regex_t & r, const string & baza) { regmatch_t matches[2]; int szukaj_od = 0; set sciagniete; while (regexec(&r, strona.c_str() + szukaj_od, 2, matches, 0) != REG_NOMATCH) { int start, dlugosc; string obrazek; string plik_obrazka; matches[1].rm_so += szukaj_od; matches[1].rm_eo += szukaj_od; start = matches[1].rm_so; dlugosc = matches[1].rm_eo - matches[1].rm_so; obrazek = strona.substr(start, dlugosc); // cout << "Obrazek: " << obrazek << endl; try { if (sciagniete.find(obrazek) == sciagniete.end()) { if (obrazek.compare(0, 7, "http://") != 0) plik_obrazka = sciagnij_plik(baza + obrazek); else plik_obrazka = sciagnij_plik(obrazek); sciagniete.insert(obrazek); } } catch (string s) { cout << "Blad podczas sciagania " << obrazek << ": " << s << endl; } strona.replace(start, dlugosc, plik_obrazka); szukaj_od = matches[1].rm_so; } } int main(int argc, char **argv) { char opt; string strona; bool sciagac_obrazki = false; while((opt = getopt(argc, argv, "m")) != EOF) { switch(opt) { case 'm': sciagac_obrazki = true; break; default: break; } } if (optind == argc) { cout << "Podaj choc jeden URL" << endl; } while (optind < argc) { try { sciagnij_plik(string(argv[optind]), sciagac_obrazki); } catch (string s) { cerr << "Blad: " << s << endl; } catch (...) { cerr << "Blad" << endl; } ++optind; } return 0; }