]> sourceware.org Git - systemtap.git/blob - client-http.cxx
Add some http client updates.
[systemtap.git] / client-http.cxx
1 // -*- C++ -*-
2 // Copyright (C) 2017 Red Hat Inc.
3 //
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
7 // later version.
8
9 #include "config.h"
10
11 #ifdef HAVE_HTTP_SUPPORT
12 #include "session.h"
13 #include "client-http.h"
14 #include "util.h"
15 #include "staptree.h"
16 #include "elaborate.h"
17
18 #include <iostream>
19 #include <sstream>
20 #include <fstream>
21 #include <map>
22 #include <vector>
23
24
25 extern "C" {
26 #include <string.h>
27 #include <curl/curl.h>
28 #include <curl/easy.h>
29 #include <json-c/json.h>
30 #include <sys/stat.h>
31 #include <ftw.h>
32 #include <rpm/rpmlib.h>
33 #include <rpm/header.h>
34 #include <rpm/rpmts.h>
35 #include <rpm/rpmdb.h>
36 #include <search.h>
37 #include <elfutils/libdwfl.h>
38 #include <elfutils/libdw.h>
39 #include <fcntl.h>
40 }
41
42 using namespace std;
43
44
45 class http_client
46 {
47 public:
48 http_client (systemtap_session &s):
49 root(0),
50 s(s),
51 curl(0),
52 retry(0),
53 location(nullptr) { }
54 ~http_client () {if (curl) curl_easy_cleanup(curl);};
55
56 json_object *root;
57 std::string host;
58 std::map<std::string, std::string> header_values;
59 enum download_type {json_type, file_type};
60
61 bool download (const std::string & url, enum download_type type);
62 bool post (const std::string & url, std::vector<std::tuple<std::string, std::string>> &request_parameters);
63 void add_script_file (std::string script_type, std::string script_file);
64 void add_module (std::string module);
65 void get_header_field (const std::string & data, const std::string & field);
66 static size_t get_data_shim (void *ptr, size_t size, size_t nitems, void *client);
67 static size_t get_file (void *ptr, size_t size, size_t nitems, FILE * stream);
68 static size_t get_header_shim (void *ptr, size_t size, size_t nitems, void *client);
69 std::string get_rpmname (std::string & pathname);
70 void get_buildid (string fname);
71 void get_kernel_buildid (void);
72
73 private:
74 size_t get_header (void *ptr, size_t size, size_t nitems);
75 size_t get_data (void *ptr, size_t size, size_t nitems);
76 static int process_buildid_shim (Dwfl_Module *dwflmod, void **userdata, const char *name,
77 Dwarf_Addr base, void *client);
78 int process_buildid (Dwfl_Module *dwflmod);
79 std::vector<std::string> script_files;
80 std::vector<std::string> modules;
81 std::vector<std::tuple<std::string, std::string>> buildids;
82 systemtap_session &s;
83 void *curl;
84 int retry;
85 std::string *location;
86 std::string buildid;
87 };
88
89 // TODO is there a better way than making this static?
90 static http_client *http;
91
92
93 size_t
94 http_client::get_data_shim (void *ptr, size_t size, size_t nitems, void *client)
95 {
96 http_client *http = static_cast<http_client *>(client);
97
98 return http->get_data (ptr, size, nitems);
99 }
100
101 // Parse the json data at PTR having SIZE and NITEMS into root
102
103 size_t
104 http_client::get_data (void *ptr, size_t size, size_t nitems)
105 {
106 string data ((const char *) ptr, (size_t) size * nitems);
107
108 if (data.front () == '{')
109 {
110 enum json_tokener_error json_error;
111 root = json_tokener_parse_verbose (data.c_str(), &json_error);
112
113 if (s.verbose >= 3)
114 clog << json_object_to_json_string (root) << endl;
115 if (root == NULL)
116 throw SEMANTIC_ERROR (json_tokener_error_desc (json_error));
117 }
118 return size * nitems;
119 }
120
121
122 size_t
123 http_client::get_header_shim (void *ptr, size_t size, size_t nitems, void *client)
124 {
125 http_client *http = static_cast<http_client *>(client);
126
127 return http->get_header (ptr, size, nitems);
128 }
129
130
131 // Extract header values at PTR having SIZE and NITEMS into header_values
132
133 size_t
134 http_client::get_header (void *ptr, size_t size, size_t nitems)
135 {
136 string data ((const char *) ptr, (size_t) size * nitems);
137
138 unsigned long colon = data.find(':');
139 if (colon != string::npos)
140 {
141 string key = data.substr (0, colon);
142 string value = data.substr (colon + 2, data.length() - colon - 4);
143 header_values[key] = value;
144 }
145
146 return size * nitems;
147 }
148
149
150 // Put the data, e.g. <module>.ko at PTR having SIZE and NITEMS into STREAM
151
152 size_t
153 http_client::get_file (void *ptr, size_t size, size_t nitems, std::FILE * stream)
154 {
155 size_t written;
156 written = fwrite (ptr, size, nitems, stream);
157 std::fflush (stream);
158 return written;
159 }
160
161
162 // Do a download of type TYPE from URL
163
164 bool
165 http_client::download (const std::string & url, http_client::download_type type)
166 {
167 struct curl_slist *headers = NULL;
168
169 if (curl)
170 curl_easy_reset (curl);
171 curl = curl_easy_init ();
172 curl_global_init (CURL_GLOBAL_ALL);
173 curl_easy_setopt (curl, CURLOPT_URL, url.c_str ());
174 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L);
175 curl_easy_setopt (curl, CURLOPT_NOSIGNAL, 1); //Prevent "longjmp causes uninitialized stack frame" bug
176 curl_easy_setopt (curl, CURLOPT_ACCEPT_ENCODING, "deflate");
177 headers = curl_slist_append (headers, "Accept: */*");
178 headers = curl_slist_append (headers, "Content-Type: text/html");
179 curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headers);
180 curl_easy_setopt (curl, CURLOPT_HTTPGET, 1);
181
182 if (type == json_type)
183 {
184 curl_easy_setopt (curl, CURLOPT_WRITEDATA, http);
185 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, http_client::get_data_shim);
186 }
187 else if (type == file_type)
188 {
189 std::string filename = url;
190 std::string ko_suffix = ".ko\"";
191 std::string filepath;
192 if (filename.back() == '/')
193 filename.erase(filename.length()-1);
194
195 if (std::equal(ko_suffix.rbegin(), ko_suffix.rend(), filename.rbegin()))
196 filepath = s.tmpdir + "/" + s.module_name + ".ko";
197 else
198 filepath = s.tmpdir + "/" + filename.substr (filename.rfind ('/')+1);
199
200 if (s.verbose >= 3)
201 clog << "Downloaded " + filepath << endl;
202 std::FILE *File = std::fopen (filepath.c_str(), "wb");
203 curl_easy_setopt (curl, CURLOPT_WRITEDATA, File);
204 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, http_client::get_file);
205 }
206 curl_easy_setopt (curl, CURLOPT_HEADERDATA, http);
207 curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, http_client::get_header_shim);
208
209 CURLcode res = curl_easy_perform (curl);
210
211 if (res != CURLE_OK)
212 {
213 clog << "curl_easy_perform() failed: " << curl_easy_strerror (res) << endl;
214 return false;
215 }
216 else
217 return true;
218 }
219
220
221 // Get the rpm corresponding to SEARCH_FILE
222
223 std::string
224 http_client::get_rpmname (std::string &search_file)
225 {
226 rpmts ts = NULL;
227 Header hdr;
228 rpmdbMatchIterator mi;
229 rpmtd td;
230
231 td = rpmtdNew ();
232 ts = rpmtsCreate ();
233
234 rpmReadConfigFiles (NULL, NULL);
235
236 int metrics[] =
237 { RPMTAG_ARCH, RPMTAG_EVR, RPMTAG_FILENAMES, RPMTAG_NAME };
238
239 struct
240 {
241 string arch;
242 string evr;
243 string filename;
244 string name;
245 } rpmhdr;
246
247 mi = rpmtsInitIterator (ts, RPMDBI_PACKAGES, NULL, 0);
248 while (NULL != (hdr = rpmdbNextIterator (mi)))
249 {
250 for (unsigned int i = 0; i < (sizeof (metrics) / sizeof (int)); i++)
251 {
252 headerGet (hdr, metrics[i], td, HEADERGET_EXT);
253 switch (td->type)
254 {
255 case RPM_STRING_TYPE:
256 {
257 const char *rpmval = rpmtdGetString (td);
258 switch (metrics[i])
259 {
260 case RPMTAG_ARCH:
261 rpmhdr.arch = strdup (rpmval);
262 break;
263 case RPMTAG_NAME:
264 rpmhdr.name = strdup (rpmval);
265 break;
266 case RPMTAG_EVR:
267 rpmhdr.evr = strdup (rpmval);
268 }
269 break;
270 }
271 case RPM_STRING_ARRAY_TYPE:
272 {
273 char **strings;
274 strings = (char**)td->data;
275 rpmhdr.filename = "";
276
277 for (unsigned int idx = 0; idx < td->count; idx++)
278 {
279 if (strcmp (strings[idx], search_file.c_str()) == 0)
280 rpmhdr.filename = strdup (strings[idx]);
281 }
282 free (td->data);
283 break;
284 }
285 }
286
287 if (metrics[i] == RPMTAG_EVR && rpmhdr.filename.length())
288 {
289 rpmdbFreeIterator (mi);
290 rpmtsFree (ts);
291 return rpmhdr.name + "-" + rpmhdr.evr + "." + rpmhdr.arch;
292 }
293
294 rpmtdReset (td);
295 }
296 }
297
298 rpmdbFreeIterator (mi);
299 rpmtsFree (ts);
300
301 return search_file;
302 }
303
304
305 // Put the buildid for DWFLMOD into buildids
306
307 int
308 http_client::process_buildid (Dwfl_Module *dwflmod)
309 {
310 const char *fname;
311 dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
312
313 GElf_Addr bias;
314 int build_id_len = 0;
315 unsigned char *build_id_bits;
316 GElf_Addr build_id_vaddr;
317 string build_id;
318 char *result = NULL;
319 int code;
320
321 dwfl_module_getelf (dwflmod, &bias);
322 build_id_len = dwfl_module_build_id (dwflmod,
323 (const unsigned char **)&build_id_bits,
324 &build_id_vaddr);
325
326 for (int i = 0; i < build_id_len; i++)
327 {
328 if (result)
329 code = asprintf (&result, "%s%02x", result, *(build_id_bits+i));
330 else
331 code = asprintf (&result, "%02x", *(build_id_bits+i));
332 if (code < 0)
333 return 1;
334 }
335
336 http->buildids.push_back(make_tuple(fname, result));
337
338 return DWARF_CB_OK;
339 }
340
341
342 int
343 http_client::process_buildid_shim (Dwfl_Module *dwflmod,
344 void **userdata __attribute__ ((unused)),
345 const char *name __attribute__ ((unused)),
346 Dwarf_Addr base __attribute__ ((unused)),
347 void *client)
348 {
349 http_client *http = static_cast<http_client *>(client);
350
351 return http->process_buildid (dwflmod);
352 }
353
354
355 // Do the setup for getting the buildid for FNAME
356
357 void
358 http_client::get_buildid (string fname)
359 {
360 int fd;
361
362 if ((fd = open (fname.c_str(), O_RDONLY)) < 0)
363 {
364 clog << "can't open " << fname;
365 return;
366 }
367
368 static const Dwfl_Callbacks callbacks =
369 {
370 dwfl_build_id_find_elf,
371 dwfl_standard_find_debuginfo,
372 dwfl_offline_section_address,
373 NULL
374 };
375 Dwfl *dwfl = dwfl_begin (&callbacks);
376
377 if (dwfl == NULL)
378 return;
379
380 if (dwfl_report_offline (dwfl, fname.c_str(), fname.c_str(), fd) == NULL)
381 return;
382 else
383 {
384 dwfl_report_end (dwfl, NULL, NULL);
385 dwfl_getmodules (dwfl, process_buildid_shim, http, 0);
386 }
387 dwfl_end (dwfl);
388 close (fd);
389 }
390
391
392 void
393 http_client::get_kernel_buildid (void)
394 {
395 const char *notesfile = "/sys/kernel/notes";
396 int fd = open (notesfile, O_RDONLY);
397 if (fd < 0)
398 return;
399
400 union
401 {
402 GElf_Nhdr nhdr;
403 unsigned char data[8192];
404 } buf;
405
406 ssize_t n = read (fd, buf.data, sizeof buf);
407 close (fd);
408
409 if (n <= 0)
410 return;
411
412 unsigned char *p = buf.data;
413 while (p < &buf.data[n])
414 {
415 /* No translation required since we are reading the native kernel. */
416 GElf_Nhdr *nhdr = (GElf_Nhdr *) p;
417 p += sizeof *nhdr;
418 unsigned char *name = p;
419 p += (nhdr->n_namesz + 3) & -4U;
420 unsigned char *bits = p;
421 p += (nhdr->n_descsz + 3) & -4U;
422
423 if (p <= &buf.data[n]
424 && nhdr->n_type == NT_GNU_BUILD_ID
425 && nhdr->n_namesz == sizeof "GNU"
426 && !memcmp (name, "GNU", sizeof "GNU"))
427 {
428 char *result = NULL;
429 int code;
430
431 for (unsigned int i = 0; i < nhdr->n_descsz; i++)
432 {
433 if (result)
434 code = asprintf (&result, "%s%02x", result, *(bits+i));
435 else
436 code = asprintf (&result, "%02x", *(bits+i));
437 if (code < 0)
438 return;
439 }
440 http->buildids.push_back(make_tuple("kernel", result));
441 break;
442 }
443 }
444 }
445
446
447 // Post REQUEST_PARAMETERS, script_files, modules, buildids to URL
448
449 bool
450 http_client::post (const std::string & url,
451 std::vector<std::tuple<std::string, std::string>> &request_parameters)
452 {
453 struct curl_slist *headers=NULL;
454 int still_running = false;
455 struct curl_httppost *formpost=NULL;
456 struct curl_httppost *lastptr=NULL;
457 CURLM *multi_handle;
458 static const char buf[] = "Expect:";
459 headers = curl_slist_append (headers, buf);
460
461 for (vector<std::tuple<std::string, std::string>>::const_iterator it = request_parameters.begin ();
462 it != request_parameters.end ();
463 ++it)
464 {
465 string parm_type = get<0>(*it);
466 char *parm_data = (char*)get<1>(*it).c_str();
467 curl_formadd (&formpost,
468 &lastptr,
469 CURLFORM_COPYNAME, parm_type.c_str(),
470 CURLFORM_COPYCONTENTS, parm_data,
471 CURLFORM_END);
472 }
473
474 // Fill in the file upload field; libcurl will load data from the given file name
475 for (vector<std::string>::const_iterator it = script_files.begin ();
476 it != script_files.end ();
477 ++it)
478 {
479 string script_file = (*it);
480 string script_base = basename (script_file.c_str());
481
482 curl_formadd (&formpost,
483 &lastptr,
484 CURLFORM_COPYNAME, script_base.c_str(),
485 CURLFORM_FILE, script_file.c_str(),
486 CURLFORM_END);
487
488 curl_formadd (&formpost,
489 &lastptr,
490 CURLFORM_COPYNAME, "files",
491 CURLFORM_COPYCONTENTS, script_file.c_str(),
492 CURLFORM_END);
493
494 // FIXME: There is no guarantee that the first file in
495 // script_files is a script - "stap -I foo/ -e '...script...'".
496 //
497 // script name is not in cmd_args so add it manually
498 if (it == script_files.begin())
499 curl_formadd (&formpost,
500 &lastptr,
501 CURLFORM_COPYNAME, "cmd_args",
502 CURLFORM_COPYCONTENTS, script_base.c_str(),
503 CURLFORM_END);
504 }
505
506 int bid_idx = 0;
507
508 for (vector<std::string>::const_iterator it = modules.begin ();
509 it != modules.end ();
510 ++it)
511 {
512 string module = (*it);
513 std::stringstream ss;
514
515 string bid_module = std::get<0>(buildids[bid_idx]);
516 string buildid = std::get<1>(buildids[bid_idx]);
517
518 ss << "{"
519 << "\"package\" : \"" << module
520 << "\", \"filename\" : \"" << bid_module
521 << "\", \"id\" : \"" << buildid
522 << "\"}";
523 curl_formadd (&formpost,
524 &lastptr,
525 CURLFORM_COPYNAME, "package info",
526 CURLFORM_CONTENTTYPE, "application/json",
527 CURLFORM_COPYCONTENTS, ss.str().c_str(),
528 CURLFORM_END);
529 bid_idx += 1;
530 }
531
532 multi_handle = curl_multi_init();
533
534 curl_easy_setopt (curl, CURLOPT_URL, url.c_str());
535 curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headers);
536 curl_easy_setopt (curl, CURLOPT_HTTPPOST, formpost);
537
538 // Mostly for debugging
539 if (s.verbose >= 4)
540 {
541 curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
542 CURL *db_curl = curl_easy_init();
543 clog << "BEGIN dump post data" << endl;
544 curl_easy_setopt(db_curl, CURLOPT_URL, "http://httpbin.org/post");
545 curl_easy_setopt (db_curl, CURLOPT_HTTPHEADER, headers);
546 curl_easy_setopt (db_curl, CURLOPT_HTTPPOST, formpost);
547 CURLcode res = curl_easy_perform (db_curl);
548 if (res != CURLE_OK)
549 clog << "curl_easy_perform() failed: " << curl_easy_strerror (res) << endl;
550 clog << "END dump post data" << endl;
551 curl_easy_cleanup (db_curl);
552 }
553
554 curl_multi_add_handle (multi_handle, curl);
555
556 curl_multi_perform (multi_handle, &still_running);
557
558 do {
559 struct timeval timeout;
560 int rc; // select() return code
561 CURLMcode mc; // curl_multi_fdset() return code
562
563 fd_set fdread;
564 fd_set fdwrite;
565 fd_set fdexcep;
566 int maxfd = -1;
567
568 long curl_timeo = -1;
569
570 FD_ZERO (&fdread);
571 FD_ZERO (&fdwrite);
572 FD_ZERO (&fdexcep);
573
574 // set a suitable timeout to play around with
575 timeout.tv_sec = 1;
576 timeout.tv_usec = 0;
577
578 curl_multi_timeout (multi_handle, &curl_timeo);
579 if (curl_timeo >= 0)
580 {
581 timeout.tv_sec = curl_timeo / 1000;
582 if (timeout.tv_sec > 1)
583 timeout.tv_sec = 1;
584 else
585 timeout.tv_usec = (curl_timeo % 1000) * 1000;
586 }
587
588 // get file descriptors from the transfers
589 mc = curl_multi_fdset (multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
590
591 if (mc != CURLM_OK)
592 {
593 clog << "curl_multi_fdset() failed" << curl_multi_strerror (mc) << endl;
594 return false;
595 }
596
597 /* On success the value of maxfd is guaranteed to be >= -1. We call
598 select(maxfd + 1, ...); specially in case of (maxfd == -1) there are
599 no fds ready yet so we call select(0, ...)to sleep 100ms,
600 the minimum suggested value */
601
602 if (maxfd == -1)
603 {
604 struct timeval wait = { 0, 100 * 1000 }; // 100ms
605 rc = select (0, NULL, NULL, NULL, &wait);
606 }
607 else
608 rc = select (maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
609
610 switch (rc)
611 {
612 case -1:
613 /* select error */
614 break;
615 case 0:
616 default:
617 curl_multi_perform (multi_handle, &still_running);
618 break;
619 }
620 } while (still_running);
621
622 curl_multi_cleanup (multi_handle);
623
624 curl_formfree (formpost);
625
626 curl_slist_free_all (headers);
627
628 return true;
629 }
630
631
632 // Add SCRIPT_FILE having SCRIPT_TYPE to script_files
633
634 void
635 http_client::add_script_file (std::string script_type, std::string script_file)
636 {
637 if (script_type == "tapset")
638 script_files.push_back (script_file);
639 else
640 script_files.insert(script_files.begin(), script_file);
641 }
642
643
644 // Add MODULE to modules
645
646 void
647 http_client::add_module (std::string module)
648 {
649 modules.push_back (module);
650 }
651
652
653 int
654 http_client_backend::initialize ()
655 {
656 http = new http_client (s);
657 request_parameters.clear();
658 request_files.clear();
659 return 0;
660 }
661
662 int
663 http_client_backend::package_request ()
664 {
665 return 0;
666 }
667
668 int
669 http_client_backend::find_and_connect_to_server ()
670 {
671 s.probes[0]->print (clog);
672
673 http->add_module ("kernel." + s.kernel_release);
674 http->get_kernel_buildid ();
675
676 for (set<std::string>::const_iterator i = s.unwindsym_modules.begin();
677 i != s.unwindsym_modules.end();
678 ++i)
679 {
680 string module = (*i);
681 string rpmname = http->get_rpmname (module);
682 http->get_buildid (module);
683 http->add_module (rpmname);
684 }
685
686 for (vector<std::string>::const_iterator i = s.http_servers.begin ();
687 i != s.http_servers.end ();
688 ++i)
689 if (http->download (*i + "/builds", http->json_type))
690 {
691 http->host = *i;
692 if (! http->post (http->host + "/builds", request_parameters))
693 return 1;
694 }
695
696 return 0;
697 }
698
699 int
700 http_client_backend::unpack_response ()
701 {
702 return 0;
703 }
704
705 int
706 http_client_backend::process_response ()
707 {
708
709 std::string::size_type found = http->host.find ("/builds");
710 std::string uri;
711 std::map<std::string, std::string>::iterator it_loc;
712 it_loc = http->header_values.find("Location");
713 if (it_loc == http->header_values.end())
714 clog << "Cannot get location from server" << endl;
715 if (found != std::string::npos)
716 uri = http->host.substr (0, found) + http->header_values["Location"];
717 else
718 uri = http->host + http->header_values["Location"];
719
720 while (true)
721 {
722 int retry = std::stoi (http->header_values["Retry-After"], nullptr, 10);
723 if (s.verbose >= 2)
724 clog << "Waiting " << retry << " seconds" << endl;
725 sleep (retry);
726 if (http->download (http->host + http->header_values["Location"], http->json_type))
727 {
728 json_object *files;
729 json_object_object_get_ex (http->root, "files", &files);
730 if (!files)
731 {
732 clog << "No files received from server" << endl;
733 return 1;
734 }
735 for (int k = 0; k < json_object_array_length (files); k++)
736 {
737 json_object *files_element = json_object_array_get_idx (files, k);
738 json_object *loc;
739 found = json_object_object_get_ex (files_element, "location", &loc);
740 string location = json_object_get_string (loc);
741 http->download (http->host + location, http->file_type);
742 }
743 break;
744 }
745 return 1;
746 }
747 json_object *stdio_loc;
748 found = json_object_object_get_ex (http->root, "stderr_location", &stdio_loc);
749 string stdio_loc_str = json_object_get_string (stdio_loc);
750 http->download (http->host + stdio_loc_str, http->file_type);
751
752 std::ifstream ferr (s.tmpdir + "/stderr");
753 if (ferr.is_open())
754 std::cout << ferr.rdbuf() << endl;
755 ferr.close();
756
757 found = json_object_object_get_ex (http->root, "stdout_location", &stdio_loc);
758 stdio_loc_str = json_object_get_string (stdio_loc);
759 http->download (http->host + stdio_loc_str, http->file_type);
760
761 std::ifstream fout (s.tmpdir + "/stdout");
762 if (fout.is_open())
763 std::cout << fout.rdbuf() << endl;
764 fout.close();
765
766 return 0;
767 }
768
769 int
770 http_client_backend::add_protocol_version (const std::string &version)
771 {
772 // Add the protocol version (so the server can ensure we're
773 // compatible).
774 request_parameters.push_back(make_tuple("version", version));
775 return 0;
776 }
777
778
779 int
780 http_client_backend::add_sysinfo ()
781 {
782 request_parameters.push_back(make_tuple("kver", s.kernel_release));
783 request_parameters.push_back(make_tuple("arch", s.architecture));
784
785 vector<string> distro_info;
786
787 get_distro_info (distro_info);
788 if (! distro_info.empty())
789 {
790 std::replace(distro_info[0].begin(), distro_info[0].end(), '\n', ' ');
791 std::replace(distro_info[1].begin(), distro_info[1].end(), '\n', ' ');
792 request_parameters.push_back(make_tuple("distro_name", distro_info[0]));
793 request_parameters.push_back(make_tuple("distro_version", distro_info[1]));
794 }
795 return 0;
796 }
797
798
799 int
800 add_tapsets (const char *name, const struct stat *status __attribute__ ((unused)), int type)
801 {
802 if (type == FTW_F)
803 http->add_script_file ("tapset", name);
804
805 return 0;
806 }
807
808
809 int
810 http_client_backend::include_file_or_directory (const std::string &script_type,
811 const std::string &script_file)
812 {
813 // FIXME: this is going to be interesting. We can't add a whole
814 // directory at one shot, we'll have to traverse the directory and
815 // add each file, preserving the directory structure somehow.
816 if (script_type == "tapset")
817 ftw (script_file.c_str(), add_tapsets, 1);
818 else
819 http->add_script_file (script_type, script_file);
820 return 0;
821 }
822
823 int
824 http_client_backend::add_tmpdir_file (const std::string &file)
825 {
826 request_files.push_back(make_tuple("files", file));
827 return 0;
828 }
829
830 int
831 http_client_backend::add_cmd_arg (const std::string &arg)
832 {
833 request_parameters.push_back(make_tuple("cmd_args", arg));
834 return 0;
835 }
836
837 void
838 http_client_backend::add_localization_variable (const std::string &,
839 const std::string &)
840 {
841 // FIXME: We'll probably just add to the request_parameters here.
842 return;
843 }
844
845 void
846 http_client_backend::add_mok_fingerprint (const std::string &)
847 {
848 // FIXME: We'll probably just add to the request_parameters here.
849 return;
850 }
851
852 #endif /* HAVE_HTTP_SUPPORT */
This page took 0.076758 seconds and 6 git commands to generate.