static void startProxy(HttpQueue *q) { #if UNUSED HttpConn *conn, *target; MprHash *hp; conn = q->conn; rx = conn->rx; loc = rx->loc; httpo uri = httpJoinUriPath(NULL, rx->parsedUri, loc->prefix); pp->target = getConnection(conn); - how to hook into the pipeline for the target if (httpConnect(pp->target, rx->method, httpUriToString(uri)) < 0) { for (mprGetFirstHash(rx->headers); hp; hp = mprGetNextHash(rx->headers, hp)) { httpSetHeader(target, hp->key, hp->data); } httpSetHeader(target, "X-Forwarded-Host", ); httpSetHeader(target, "Host", ); httpSetHeader(target, "X-Forwarded-Server", ); httpSetHeader(target, "X-Forwarded-For", ); } // Push headers out - this may not work httpFlush(conn); #endif }
/* function flush(dir: Number = Stream.WRITE): Void */ static EjsObj *http_flush(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { int dir; dir = (argc == 1) ? ejsGetInt(ejs, argv[0]) : EJS_STREAM_WRITE; if (dir & EJS_STREAM_WRITE) { httpFlush(hp->conn); } return 0; }
static int sendRequest(HttpConn *conn, cchar *method, cchar *url, MprList *files) { if (httpConnect(conn, method, url, app->ssl) < 0) { mprLog("error http", 0, "Cannot process request for \"%s\"\n%s", url, httpGetError(conn)); return MPR_ERR_CANT_OPEN; } /* This program does not do full-duplex writes with reads. ie. if you have a request that sends and receives data in parallel -- http will do the writes first then read the response. */ if (app->bodyData || app->formData || files) { if (app->chunkSize > 0) { httpSetChunkSize(conn, app->chunkSize); } if (writeBody(conn, files) < 0) { mprLog("error http", 0, "Cannot write body data to \"%s\". %s", url, httpGetError(conn)); return MPR_ERR_CANT_WRITE; } } assert(!mprGetCurrentThread()->yielded); httpFinalizeOutput(conn); httpFlush(conn); return 0; }
http_status_t /* O - Initial HTTP status */ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - Resource path */ size_t length) /* I - Length of data to follow or @code CUPS_LENGTH_VARIABLE@ */ { http_status_t status; /* Status of HTTP request */ int got_status; /* Did we get the status? */ ipp_state_t state; /* State of IPP processing */ http_status_t expect; /* Expect: header to use */ DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", " "length=" CUPS_LLFMT ")", http, request, request ? ippOpString(request->request.op.operation_id) : "?", resource, CUPS_LLCAST length)); /* * Range check input... */ if (!request || !resource) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (HTTP_STATUS_ERROR); } /* * Get the default connection as needed... */ if (!http) if ((http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * If the prior request was not flushed out, do so now... */ if (http->state == HTTP_STATE_GET_SEND || http->state == HTTP_STATE_POST_SEND) { DEBUG_puts("2cupsSendRequest: Flush prior response."); httpFlush(http); } else if (http->state != HTTP_STATE_WAITING) { DEBUG_printf(("1cupsSendRequest: Unknown HTTP state (%d), " "reconnecting.", http->state)); if (httpReconnect2(http, 30000, NULL)) return (HTTP_STATUS_ERROR); } #ifdef HAVE_SSL /* * See if we have an auth-info attribute and are communicating over * a non-local link. If so, encrypt the link so that we can pass * the authentication information securely... */ if (ippFindAttribute(request, "auth-info", IPP_TAG_TEXT) && !httpAddrLocalhost(http->hostaddr) && !http->tls && httpEncryption(http, HTTP_ENCRYPTION_REQUIRED)) { DEBUG_puts("1cupsSendRequest: Unable to encrypt connection."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } #endif /* HAVE_SSL */ /* * Reconnect if the last response had a "Connection: close"... */ if (!_cups_strcasecmp(http->fields[HTTP_FIELD_CONNECTION], "close")) { DEBUG_puts("2cupsSendRequest: Connection: close"); httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } } /* * Loop until we can send the request without authorization problems. */ expect = HTTP_STATUS_CONTINUE; for (;;) { DEBUG_puts("2cupsSendRequest: Setup..."); /* * Setup the HTTP variables needed... */ httpClearFields(http); httpSetExpect(http, expect); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); httpSetLength(http, length); #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9)) { /* * Do not use cached Kerberos credentials since they will look like a * "replay" attack... */ _cupsSetNegotiateAuthString(http, "POST", resource); } #endif /* HAVE_GSSAPI */ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); DEBUG_printf(("2cupsSendRequest: authstring=\"%s\"", http->authstring)); /* * Try the request... */ DEBUG_puts("2cupsSendRequest: Sending HTTP POST..."); if (httpPost(http, resource)) { DEBUG_puts("2cupsSendRequest: POST failed, reconnecting."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } else continue; } /* * Send the IPP data... */ DEBUG_puts("2cupsSendRequest: Writing IPP request..."); request->state = IPP_STATE_IDLE; status = HTTP_STATUS_CONTINUE; got_status = 0; while ((state = ippWrite(http, request)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; else if (httpCheck(http)) { got_status = 1; _httpUpdate(http, &status); if (status >= HTTP_STATUS_MULTIPLE_CHOICES) break; } if (state == IPP_STATE_ERROR) { DEBUG_puts("1cupsSendRequest: Unable to send IPP request."); http->status = HTTP_STATUS_ERROR; http->state = HTTP_STATE_WAITING; return (HTTP_STATUS_ERROR); } /* * Wait up to 1 second to get the 100-continue response as needed... */ if (!got_status) { if (expect == HTTP_STATUS_CONTINUE) { DEBUG_puts("2cupsSendRequest: Waiting for 100-continue..."); if (httpWait(http, 1000)) _httpUpdate(http, &status); } else if (httpCheck(http)) _httpUpdate(http, &status); } DEBUG_printf(("2cupsSendRequest: status=%d", status)); /* * Process the current HTTP status... */ if (status >= HTTP_STATUS_MULTIPLE_CHOICES) { int temp_status; /* Temporary status */ _cupsSetHTTPError(status); do { temp_status = httpUpdate(http); } while (temp_status != HTTP_STATUS_ERROR && http->state == HTTP_STATE_POST_RECV); httpFlush(http); } switch (status) { case HTTP_STATUS_CONTINUE : case HTTP_STATUS_OK : case HTTP_STATUS_ERROR : DEBUG_printf(("1cupsSendRequest: Returning %d.", status)); return (status); case HTTP_STATUS_UNAUTHORIZED : if (cupsDoAuthentication(http, "POST", resource)) { DEBUG_puts("1cupsSendRequest: Returning HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED."); return (HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED); } DEBUG_puts("2cupsSendRequest: Reconnecting after HTTP_STATUS_UNAUTHORIZED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; #ifdef HAVE_SSL case HTTP_STATUS_UPGRADE_REQUIRED : /* * Flush any error message, reconnect, and then upgrade with * encryption... */ DEBUG_puts("2cupsSendRequest: Reconnecting after " "HTTP_STATUS_UPGRADE_REQUIRED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } DEBUG_puts("2cupsSendRequest: Upgrading to TLS."); if (httpEncryption(http, HTTP_ENCRYPTION_REQUIRED)) { DEBUG_puts("1cupsSendRequest: Unable to encrypt connection."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; #endif /* HAVE_SSL */ case HTTP_STATUS_EXPECTATION_FAILED : /* * Don't try using the Expect: header the next time around... */ expect = (http_status_t)0; DEBUG_puts("2cupsSendRequest: Reconnecting after " "HTTP_EXPECTATION_FAILED."); if (httpReconnect2(http, 30000, NULL)) { DEBUG_puts("1cupsSendRequest: Unable to reconnect."); return (HTTP_STATUS_SERVICE_UNAVAILABLE); } break; default : /* * Some other error... */ return (status); } } }
ipp_t * /* O - Response or @code NULL@ on HTTP error */ cupsGetResponse(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource) /* I - HTTP resource for POST */ { http_status_t status; /* HTTP status */ ipp_state_t state; /* IPP read state */ ipp_t *response = NULL; /* IPP response */ DEBUG_printf(("cupsGetResponse(http=%p, resource=\"%s\")", http, resource)); /* * Connect to the default server as needed... */ if (!http) http = _cupsConnect(); if (!http || (http->state != HTTP_STATE_POST_RECV && http->state != HTTP_STATE_POST_SEND)) return (NULL); /* * Check for an unfinished chunked request... */ if (http->data_encoding == HTTP_ENCODING_CHUNKED) { /* * Send a 0-length chunk to finish off the request... */ DEBUG_puts("2cupsGetResponse: Finishing chunked POST..."); if (httpWrite2(http, "", 0) < 0) return (NULL); } /* * Wait for a response from the server... */ DEBUG_printf(("2cupsGetResponse: Update loop, http->status=%d...", http->status)); do { status = httpUpdate(http); } while (status == HTTP_STATUS_CONTINUE); DEBUG_printf(("2cupsGetResponse: status=%d", status)); if (status == HTTP_STATUS_OK) { /* * Get the IPP response... */ response = ippNew(); while ((state = ippRead(http, response)) != IPP_STATE_DATA) if (state == IPP_STATE_ERROR) break; if (state == IPP_STATE_ERROR) { /* * Flush remaining data and delete the response... */ DEBUG_puts("1cupsGetResponse: IPP read error!"); httpFlush(http); ippDelete(response); response = NULL; http->status = status = HTTP_STATUS_ERROR; http->error = EINVAL; } } else if (status != HTTP_STATUS_ERROR) { /* * Flush any error message... */ httpFlush(http); /* * Then handle encryption and authentication... */ if (status == HTTP_STATUS_UNAUTHORIZED) { /* * See if we can do authentication... */ DEBUG_puts("2cupsGetResponse: Need authorization..."); if (!cupsDoAuthentication(http, "POST", resource)) httpReconnect2(http, 30000, NULL); else http->status = status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* * Force a reconnect with encryption... */ DEBUG_puts("2cupsGetResponse: Need encryption..."); if (!httpReconnect2(http, 30000, NULL)) httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); } #endif /* HAVE_SSL */ } if (response) { ipp_attribute_t *attr; /* status-message attribute */ attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); DEBUG_printf(("1cupsGetResponse: status-code=%s, status-message=\"%s\"", ippErrorString(response->request.status.status_code), attr ? attr->values[0].string.text : "")); _cupsSetError(response->request.status.status_code, attr ? attr->values[0].string.text : ippErrorString(response->request.status.status_code), 0); } return (response); }
ipp_t * /* O - Response data */ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ ipp_t *request, /* I - IPP request */ const char *resource, /* I - HTTP resource for POST */ int infile, /* I - File to read from or -1 for none */ int outfile) /* I - File to write to or -1 for none */ { ipp_t *response = NULL; /* IPP response data */ size_t length = 0; /* Content-Length value */ http_status_t status; /* Status of HTTP request */ struct stat fileinfo; /* File information */ int bytes; /* Number of bytes read/written */ char buffer[32768]; /* Output buffer */ DEBUG_printf(("cupsDoIORequest(http=%p, request=%p(%s), resource=\"%s\", " "infile=%d, outfile=%d)", http, request, request ? ippOpString(request->request.op.operation_id) : "?", resource, infile, outfile)); /* * Range check input... */ if (!request || !resource) { ippDelete(request); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } /* * Get the default connection as needed... */ if (!http) if ((http = _cupsConnect()) == NULL) { ippDelete(request); return (NULL); } /* * See if we have a file to send... */ if (infile >= 0) { if (fstat(infile, &fileinfo)) { /* * Can't get file information! */ _cupsSetError(errno == EBADF ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, NULL, 0); ippDelete(request); return (NULL); } #ifdef WIN32 if (fileinfo.st_mode & _S_IFDIR) #else if (S_ISDIR(fileinfo.st_mode)) #endif /* WIN32 */ { /* * Can't send a directory... */ ippDelete(request); _cupsSetError(IPP_STATUS_ERROR_NOT_POSSIBLE, strerror(EISDIR), 0); return (NULL); } #ifndef WIN32 if (!S_ISREG(fileinfo.st_mode)) length = 0; /* Chunk when piping */ else #endif /* !WIN32 */ length = ippLength(request) + fileinfo.st_size; } else length = ippLength(request); DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld", (long)ippLength(request), (long)length)); /* * Clear any "Local" authentication data since it is probably stale... */ if (http->authstring && !strncmp(http->authstring, "Local ", 6)) httpSetAuthString(http, NULL, NULL); /* * Loop until we can send the request without authorization problems. */ while (response == NULL) { DEBUG_puts("2cupsDoIORequest: setup..."); /* * Send the request... */ status = cupsSendRequest(http, request, resource, length); DEBUG_printf(("2cupsDoIORequest: status=%d", status)); if (status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA && infile >= 0) { DEBUG_puts("2cupsDoIORequest: file write..."); /* * Send the file with the request... */ #ifndef WIN32 if (S_ISREG(fileinfo.st_mode)) #endif /* WIN32 */ lseek(infile, 0, SEEK_SET); while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0) { if ((status = cupsWriteRequestData(http, buffer, bytes)) != HTTP_STATUS_CONTINUE) break; } } /* * Get the server's response... */ if (status != HTTP_STATUS_ERROR) { response = cupsGetResponse(http, resource); status = httpGetStatus(http); } DEBUG_printf(("2cupsDoIORequest: status=%d", status)); if (status == HTTP_STATUS_ERROR || (status >= HTTP_STATUS_BAD_REQUEST && status != HTTP_STATUS_UNAUTHORIZED && status != HTTP_STATUS_UPGRADE_REQUIRED)) { _cupsSetHTTPError(status); break; } if (response && outfile >= 0) { /* * Write trailing data to file... */ while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0) if (write(outfile, buffer, bytes) < bytes) break; } if (http->state != HTTP_STATE_WAITING) { /* * Flush any remaining data... */ httpFlush(http); } } /* * Delete the original request and return the response... */ ippDelete(request); return (response); }
int /* O - 1 on success, 0 on error */ translate_messages(cups_array_t *cat, /* I - Message catalog */ const char *lang) /* I - Output language... */ { /* * Google provides a simple translation/language tool for translating * from one language to another. It is far from perfect, however it * can be used to get a basic translation done or update an existing * translation when no other resources are available. * * Translation requests are sent as HTTP POSTs to * "http://translate.google.com/translate_t" with the following form * variables: * * Name Description Value * -------- ---------------------------------- ---------------- * hl Help language? "en" * ie Input encoding "UTF8" * langpair Language pair "en|" + language * oe Output encoding "UTF8" * text Text to translate translation string */ int ret; /* Return value */ _cups_message_t *m; /* Current message */ int tries; /* Number of tries... */ http_t *http; /* HTTP connection */ http_status_t status; /* Status of POST request */ char *idptr, /* Pointer into msgid */ buffer[65536], /* Input/output buffer */ *bufptr, /* Pointer into buffer */ *bufend, /* Pointer to end of buffer */ length[16]; /* Content length */ int bytes; /* Number of bytes read */ /* * Connect to translate.google.com... */ puts("Connecting to translate.google.com..."); if ((http = httpConnect("translate.google.com", 80)) == NULL) { perror("Unable to connect to translate.google.com"); return (0); } /* * Scan the current messages, requesting a translation of any untranslated * messages... */ for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1; m; m = (_cups_message_t *)cupsArrayNext(cat)) { /* * Skip messages that are already translated... */ if (m->str && m->str[0]) continue; /* * Encode the form data into the buffer... */ snprintf(buffer, sizeof(buffer), "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang); bufptr = buffer + strlen(buffer); bufend = buffer + sizeof(buffer) - 5; for (idptr = m->id; *idptr && bufptr < bufend; idptr ++) if (*idptr == ' ') *bufptr++ = '+'; else if (*idptr < ' ' || *idptr == '%') { sprintf(bufptr, "%%%02X", *idptr & 255); bufptr += 3; } else if (*idptr != '&') *bufptr++ = *idptr; *bufptr++ = '&'; *bufptr = '\0'; sprintf(length, "%d", (int)(bufptr - buffer)); /* * Send the request... */ printf("\"%s\" = ", m->id); fflush(stdout); tries = 0; do { httpClearFields(http); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/x-www-form-urlencoded"); httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); if (httpPost(http, "/translate_t")) { httpReconnect(http); httpPost(http, "/translate_t"); } httpWrite2(http, buffer, bufptr - buffer); while ((status = httpUpdate(http)) == HTTP_CONTINUE); if (status != HTTP_OK && status != HTTP_ERROR) httpFlush(http); tries ++; } while (status == HTTP_ERROR && tries < 10); if (status == HTTP_OK) { /* * OK, read the translation back... */ bufptr = buffer; bufend = buffer + sizeof(buffer) - 1; while ((bytes = httpRead2(http, bufptr, bufend - bufptr)) > 0) bufptr += bytes; if (bytes < 0) { /* * Read error, abort! */ puts("READ ERROR!"); ret = 0; break; } *bufptr = '\0'; /* * Find the div containing translation */ if ((bufptr = strstr(buffer, "<div id=result_box")) == NULL) { /* * No textarea, abort! */ puts("NO div id=result_box!"); ret = 0; break; } if ((bufptr = strchr(bufptr, '>')) == NULL) { /* * textarea doesn't end, abort! */ puts("DIV SHORT DATA!"); ret = 0; break; } bufptr ++; if ((bufend = strstr(bufptr, "</div>")) == NULL) { /* * textarea doesn't close, abort! */ puts("/DIV SHORT DATA!"); ret = 0; break; } *bufend = '\0'; /* * Copy the translation... */ m->str = strdup(bufptr); /* * Convert character entities to regular chars... */ for (bufptr = strchr(m->str, '&'); bufptr; bufptr = strchr(bufptr + 1, '&')) { if (!strncmp(bufptr, "<", 4)) { *bufptr = '<'; _cups_strcpy(bufptr + 1, bufptr + 4); } else if (!strncmp(bufptr, ">", 4)) { *bufptr = '>'; _cups_strcpy(bufptr + 1, bufptr + 4); } else if (!strncmp(bufptr, "&", 5)) _cups_strcpy(bufptr + 1, bufptr + 5); } printf("\"%s\"\n", m->str); } else if (status == HTTP_ERROR) { printf("NETWORK ERROR (%s)!\n", strerror(httpError(http))); ret = 0; break; } else { printf("HTTP ERROR %d!\n", status); ret = 0; break; } } httpClose(http); return (ret); }
ipp_status_t /* O - Request status - @code IPP_OK@ on success. */ cupsGetDevices( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ int timeout, /* I - Timeout in seconds or @code CUPS_TIMEOUT_DEFAULT@ */ const char *include_schemes, /* I - Comma-separated URI schemes to include or @code CUPS_INCLUDE_ALL@ */ const char *exclude_schemes, /* I - Comma-separated URI schemes to exclude or @code CUPS_EXCLUDE_NONE@ */ cups_device_cb_t callback, /* I - Callback function */ void *user_data) /* I - User data pointer */ { ipp_t *request, /* CUPS-Get-Devices request */ *response; /* CUPS-Get-Devices response */ ipp_attribute_t *attr; /* Current attribute */ const char *device_class, /* device-class value */ *device_id, /* device-id value */ *device_info, /* device-info value */ *device_location, /* device-location value */ *device_make_and_model, /* device-make-and-model value */ *device_uri; /* device-uri value */ int blocking; /* Current blocking-IO mode */ cups_option_t option; /* in/exclude-schemes option */ http_status_t status; /* HTTP status of request */ ipp_state_t state; /* IPP response state */ /* * Range check input... */ DEBUG_printf(("cupsGetDevices(http=%p, timeout=%d, include_schemes=\"%s\", exclude_schemes=\"%s\", callback=%p, user_data=%p)", (void *)http, timeout, include_schemes, exclude_schemes, (void *)callback, user_data)); if (!callback) return (IPP_STATUS_ERROR_INTERNAL); if (!http) http = _cupsConnect(); if (!http) return (IPP_STATUS_ERROR_SERVICE_UNAVAILABLE); /* * Create a CUPS-Get-Devices request... */ request = ippNewRequest(IPP_OP_CUPS_GET_DEVICES); if (timeout > 0) ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "timeout", timeout); if (include_schemes) { option.name = "include-schemes"; option.value = (char *)include_schemes; cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION); } if (exclude_schemes) { option.name = "exclude-schemes"; option.value = (char *)exclude_schemes; cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION); } /* * Send the request and do any necessary authentication... */ do { DEBUG_puts("2cupsGetDevices: Sending request..."); status = cupsSendRequest(http, request, "/", ippLength(request)); DEBUG_puts("2cupsGetDevices: Waiting for response status..."); while (status == HTTP_STATUS_CONTINUE) status = httpUpdate(http); if (status != HTTP_STATUS_OK) { httpFlush(http); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * See if we can do authentication... */ DEBUG_puts("2cupsGetDevices: Need authorization..."); if (!cupsDoAuthentication(http, "POST", "/")) httpReconnect2(http, 30000, NULL); else { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* * Force a reconnect with encryption... */ DEBUG_puts("2cupsGetDevices: Need encryption..."); if (!httpReconnect2(http, 30000, NULL)) httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); } #endif /* HAVE_SSL */ } } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); DEBUG_printf(("2cupsGetDevices: status=%d", status)); ippDelete(request); if (status != HTTP_STATUS_OK) { _cupsSetHTTPError(status); return (cupsLastError()); } /* * Read the response in non-blocking mode... */ blocking = httpGetBlocking(http); httpBlocking(http, 0); response = ippNew(); device_class = NULL; device_id = NULL; device_info = NULL; device_location = ""; device_make_and_model = NULL; device_uri = NULL; attr = NULL; DEBUG_puts("2cupsGetDevices: Reading response..."); do { if ((state = ippRead(http, response)) == IPP_STATE_ERROR) break; DEBUG_printf(("2cupsGetDevices: state=%d, response->last=%p", state, (void *)response->last)); if (!response->attrs) continue; while (attr != response->last) { if (!attr) attr = response->attrs; else attr = attr->next; DEBUG_printf(("2cupsGetDevices: attr->name=\"%s\", attr->value_tag=%d", attr->name, attr->value_tag)); if (!attr->name) { if (device_class && device_id && device_info && device_make_and_model && device_uri) (*callback)(device_class, device_id, device_info, device_make_and_model, device_uri, device_location, user_data); device_class = NULL; device_id = NULL; device_info = NULL; device_location = ""; device_make_and_model = NULL; device_uri = NULL; } else if (!strcmp(attr->name, "device-class") && attr->value_tag == IPP_TAG_KEYWORD) device_class = attr->values[0].string.text; else if (!strcmp(attr->name, "device-id") && attr->value_tag == IPP_TAG_TEXT) device_id = attr->values[0].string.text; else if (!strcmp(attr->name, "device-info") && attr->value_tag == IPP_TAG_TEXT) device_info = attr->values[0].string.text; else if (!strcmp(attr->name, "device-location") && attr->value_tag == IPP_TAG_TEXT) device_location = attr->values[0].string.text; else if (!strcmp(attr->name, "device-make-and-model") && attr->value_tag == IPP_TAG_TEXT) device_make_and_model = attr->values[0].string.text; else if (!strcmp(attr->name, "device-uri") && attr->value_tag == IPP_TAG_URI) device_uri = attr->values[0].string.text; } } while (state != IPP_STATE_DATA); DEBUG_printf(("2cupsGetDevices: state=%d, response->last=%p", state, (void *)response->last)); if (device_class && device_id && device_info && device_make_and_model && device_uri) (*callback)(device_class, device_id, device_info, device_make_and_model, device_uri, device_location, user_data); /* * Set the IPP status and return... */ httpBlocking(http, blocking); httpFlush(http); if (status == HTTP_STATUS_ERROR) _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(http->error), 0); else { attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); DEBUG_printf(("cupsGetDevices: status-code=%s, status-message=\"%s\"", ippErrorString(response->request.status.status_code), attr ? attr->values[0].string.text : "")); _cupsSetError(response->request.status.status_code, attr ? attr->values[0].string.text : ippErrorString(response->request.status.status_code), 0); } ippDelete(response); return (cupsLastError()); }
void translate_messages(const char *language)/* I - Output language... */ { /* * Google provides a simple translation/language tool for translating * from one language to another. It is far from perfect, however it * can be used to get a basic translation done or update an existing * translation when no other resources are available. * * Translation requests are sent as HTTP POSTs to * "http://translate.google.com/translate_t" with the following form * variables: * * Name Description Value * -------- ---------------------------------- ---------------- * hl Help language? "en" * ie Input encoding "UTF8" * langpair Language pair "en|" + language * oe Output encoding "UTF8" * text Text to translate translation string */ int i; /* Looping var */ message_t *m; /* Current message */ int tries; /* Number of tries... */ http_t *http; /* HTTP connection */ http_status_t status; /* Status of POST request */ char *idptr, /* Pointer into msgid */ *strptr, /* Pointer into msgstr */ buffer[65536], /* Input/output buffer */ *bufptr, /* Pointer into buffer */ *bufend, /* Pointer to end of buffer */ length[16]; /* Content length */ unsigned char *utf8; /* UTF-8 string */ int ch; /* Current decoded character */ int bytes; /* Number of bytes read */ /* * Connect to translate.google.com... */ puts("Connecting to translate.google.com..."); if ((http = httpConnect("translate.google.com", 80)) == NULL) { perror("Unable to connect to translate.google.com"); return; } /* * Scan the current messages, requesting a translation of any untranslated * messages... */ for (i = num_messages, m = messages; i > 0; i --, m ++) { /* * Skip messages that are already translated... */ if (m->str && m->str[0]) continue; /* * Encode the form data into the buffer... */ snprintf(buffer, sizeof(buffer), "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", language); bufptr = buffer + strlen(buffer); bufend = buffer + sizeof(buffer) - 5; for (idptr = m->id; *idptr && bufptr < bufend; idptr ++) if (*idptr == ' ') *bufptr++ = '+'; else if (*idptr < ' ' || *idptr == '%') { sprintf(bufptr, "%%%02X", *idptr & 255); bufptr += 3; } else if (*idptr != '&') *bufptr++ = *idptr; *bufptr++ = '&'; *bufptr = '\0'; sprintf(length, "%d", bufptr - buffer); /* * Send the request... */ printf("\"%s\" = ", m->id); fflush(stdout); tries = 0; do { httpClearFields(http); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/x-www-form-urlencoded"); httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); if (httpPost(http, "/translate_t")) { httpReconnect(http); httpPost(http, "/translate_t"); } httpWrite(http, buffer, bufptr - buffer); while ((status = httpUpdate(http)) == HTTP_CONTINUE); if (status != HTTP_OK && status != HTTP_ERROR) httpFlush(http); tries ++; } while (status == HTTP_ERROR && tries < 10); if (status == HTTP_OK) { /* * OK, read the translation back... */ bufptr = buffer; bufend = buffer + sizeof(buffer) - 1; while ((bytes = httpRead(http, bufptr, bufend - bufptr)) > 0) bufptr += bytes; if (bytes < 0) { /* * Read error, abort! */ puts("READ ERROR!"); break; } *bufptr = '\0'; /* * Find the first textarea element - that will have the translation data... */ if ((bufptr = strstr(buffer, "<textarea")) == NULL) { /* * No textarea, abort! */ puts("NO TEXTAREA!"); break; } if ((bufptr = strchr(bufptr, '>')) == NULL) { /* * textarea doesn't end, abort! */ puts("TEXTAREA SHORT DATA!"); break; } utf8 = (unsigned char *)bufptr + 1; if ((bufend = strstr(bufptr, "</textarea>")) == NULL) { /* * textarea doesn't close, abort! */ puts("/TEXTAREA SHORT DATA!"); break; } *bufend = '\0'; /* * Copy the UTF-8 translation to ISO-8859-1 (for now)... */ m->str = malloc(bufend - bufptr); for (strptr = m->str; *utf8;) if (*utf8 < 0x80) *strptr++ = *utf8++; else { if ((*utf8 & 0xe0) == 0xc0) { /* * Two-byte encoding... */ ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f); utf8 += 2; } else if ((ch & 0xf0) == 0xe0) { /* * Three-byte encoding... */ ch = ((((utf8[0] & 0x0f) << 6) | (utf8[1] & 0x3f)) << 6) | (utf8[2] & 0x3f); utf8 += 3; } if (ch < 256) /* ISO-8859-1 */ *strptr++ = ch; else if (ch == 0x20ac) /* Euro */ *strptr++ = 0xA4; /* ISO-8859-15 mapping */ } *strptr = '\0'; printf("\"%s\"\n", m->str); } else if (status == HTTP_ERROR) { printf("NETWORK ERROR (%s)!\n", strerror(httpError(http))); break; } else { printf("HTTP ERROR %d!\n", status); break; } } httpClose(http); }
http_status_t /* O - HTTP status */ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { ssize_t bytes; /* Number of bytes read */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ char if_modified_since[HTTP_MAX_VALUE]; /* If-Modified-Since header */ int new_auth = 0; /* Using new auth information? */ int digest; /* Are we using Digest authentication? */ /* * Range check input... */ DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd)); if (!resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } if (!http) if ((http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * Then send GET requests to the HTTP server... */ strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE), sizeof(if_modified_since)); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since); digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); if (digest && !new_auth) { /* * Update the Digest authentication string... */ _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); } #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) { /* * Do not use cached Kerberos credentials since they will look like a * "replay" attack... */ _cupsSetNegotiateAuthString(http, "GET", resource); } #endif /* HAVE_GSSAPI */ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } new_auth = 0; while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ new_auth = 1; if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); /* * See if we actually got the file or an error... */ if (status == HTTP_STATUS_OK) { /* * Yes, copy the file... */ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) write(fd, buffer, (size_t)bytes); } else { _cupsSetHTTPError(status); httpFlush(http); } /* * Return the request status... */ DEBUG_printf(("1cupsGetFd: Returning %d...", status)); return (status); }
http_status_t /* O - HTTP status */ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { ssize_t bytes; /* Number of bytes read */ int retries; /* Number of retries */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ int new_auth = 0; /* Using new auth information? */ int digest; /* Are we using Digest authentication? */ /* * Range check input... */ DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)", (void *)http, resource, fd)); if (!resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_STATUS_ERROR); } if (!http) if ((http = _cupsConnect()) == NULL) return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * Then send PUT requests to the HTTP server... */ retries = 0; do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } DEBUG_printf(("2cupsPutFd: starting attempt, authstring=\"%s\"...", http->authstring)); httpClearFields(http); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetExpect(http, HTTP_STATUS_CONTINUE); digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); if (digest && !new_auth) { /* * Update the Digest authentication string... */ _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource); } #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) { /* * Do not use cached Kerberos credentials since they will look like a * "replay" attack... */ _cupsSetNegotiateAuthString(http, "PUT", resource); } #endif /* HAVE_GSSAPI */ httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); if (httpPut(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } /* * Wait up to 1 second for a 100-continue response... */ if (httpWait(http, 1000)) status = httpUpdate(http); else status = HTTP_STATUS_CONTINUE; if (status == HTTP_STATUS_CONTINUE) { /* * Copy the file... */ lseek(fd, 0, SEEK_SET); while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) if (httpCheck(http)) { if ((status = httpUpdate(http)) != HTTP_STATUS_CONTINUE) break; } else httpWrite2(http, buffer, (size_t)bytes); } if (status == HTTP_STATUS_CONTINUE) { httpWrite2(http, buffer, 0); while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); } if (status == HTTP_STATUS_ERROR && !retries) { DEBUG_printf(("2cupsPutFd: retry on status %d", status)); retries ++; /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Try again... */ continue; } DEBUG_printf(("2cupsPutFd: status=%d", status)); new_auth = 0; if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ new_auth = 1; if (cupsDoAuthentication(http, "PUT", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED || (status == HTTP_STATUS_ERROR && retries < 2)); /* * See if we actually put the file or an error... */ if (status != HTTP_STATUS_CREATED) { _cupsSetHTTPError(status); httpFlush(http); } DEBUG_printf(("1cupsPutFd: Returning %d...", status)); return (status); }
void espFlush(HttpConn *conn) { httpFlush(conn); }
char * /* O - Pathname or NULL */ file_find(const char *path, /* I - Path "dir;dir;dir" */ const char *s) /* I - File to find */ { int i; /* Looping var */ int retry; /* Current retry */ char *temp, /* Current position in filename */ method[HTTP_MAX_URI], /* Method/scheme */ username[HTTP_MAX_URI], /* Username:password */ hostname[HTTP_MAX_URI], /* Hostname */ resource[HTTP_MAX_URI]; /* Resource */ int port; /* Port number */ const char *connhost; /* Host to connect to */ int connport; /* Port to connect to */ char connpath[HTTP_MAX_URI], /* Path for GET */ connauth[HTTP_MAX_VALUE];/* Auth string */ http_status_t status; /* Status of request... */ FILE *fp; /* Web file */ int bytes, /* Bytes read */ count, /* Number of bytes so far */ total; /* Total bytes in file */ static char filename[HTTP_MAX_URI]; /* Current filename */ /* * If the filename is NULL, return NULL... */ if (s == NULL) return (NULL); if (strncmp(s, "http:", 5) == 0 || (path != NULL && strncmp(path, "http:", 5) == 0)) strcpy(method, "http"); #ifdef HAVE_LIBSSL else if (strncmp(s, "https:", 6) == 0 || (path != NULL && strncmp(path, "https:", 6) == 0)) strcpy(method, "https"); #endif /* HAVE_LIBSSL */ else strcpy(method, "file"); if (strcmp(method, "file") == 0) { /* * If the path is NULL or empty, return the filename... */ if (path == NULL || !path[0]) return ((char *)s); /* * Else loop through the path string until we reach the end... */ while (*path != '\0') { /* * Copy the path directory... */ temp = filename; while (*path != ';' && *path && temp < (filename + sizeof(filename) - 1)) *temp++ = *path++; if (*path == ';') path ++; /* * Append a slash as needed... */ if (temp > filename && temp < (filename + sizeof(filename) - 1) && s[0] != '/') *temp++ = '/'; /* * Append the filename... */ strncpy(temp, s, sizeof(filename) - (temp - filename)); filename[sizeof(filename) - 1] = '\0'; /* * See if the file exists... */ if (!access(filename, 0)) return (filename); } } else { /* * Remote file; look it up in the web cache, and then try getting it * from the remote system... */ for (i = 0; i < web_files; i ++) if (web_cache[i].url && strcmp(web_cache[i].url, s) == 0) return (web_cache[i].name); #ifdef HAVE_LIBSSL if (strncmp(s, "http:", 5) == 0 || strncmp(s, "https:", 6) == 0) #else if (strncmp(s, "http:", 5) == 0) #endif /* HAVE_LIBSSL */ httpSeparate(s, method, username, hostname, &port, resource); else if (s[0] == '/') { httpSeparate(path, method, username, hostname, &port, resource); strcpy(resource, s); } else { if (strncmp(s, "./", 2) == 0) snprintf(filename, sizeof(filename), "%s/%s", path, s + 2); else snprintf(filename, sizeof(filename), "%s/%s", path, s); httpSeparate(filename, method, username, hostname, &port, resource); } for (status = HTTP_ERROR, retry = 0; status == HTTP_ERROR && retry < 5; retry ++) { if (proxy_port) { /* * Send request to proxy host... */ connhost = proxy_host; connport = proxy_port; snprintf(connpath, sizeof(connpath), "%s://%s:%d%s", method, hostname, port, resource); } else { /* * Send request to host directly... */ connhost = hostname; connport = port; strcpy(connpath, resource); } if (http != NULL && strcasecmp(http->hostname, hostname) != 0) { httpClose(http); http = NULL; } if (http == NULL) { progress_show("Connecting to %s...", connhost); atexit(file_cleanup); #ifdef HAVE_LIBSSL if (strcmp(method, "http") == 0) http = httpConnect(connhost, connport); else http = httpConnectEncrypt(connhost, connport, HTTP_ENCRYPT_ALWAYS); #else http = httpConnect(connhost, connport); #endif /* HAVE_LIBSSL */ if (http == NULL) { progress_hide(); progress_error("Unable to connect to %s!", connhost); return (NULL); } } progress_show("Getting %s...", connpath); httpClearFields(http); httpSetField(http, HTTP_FIELD_HOST, hostname); httpSetField(http, HTTP_FIELD_USER_AGENT, "HTMLDOC v" SVERSION); httpSetField(http, HTTP_FIELD_CONNECTION, "Keep-Alive"); if (username[0]) { strcpy(connauth, "Basic "); httpEncode64(connauth + 6, username); httpSetField(http, HTTP_FIELD_AUTHORIZATION, connauth); } if (!httpGet(http, connpath)) while ((status = httpUpdate(http)) == HTTP_CONTINUE); else status = HTTP_ERROR; if (status >= HTTP_MOVED_PERMANENTLY && status <= HTTP_SEE_OTHER) { /* * Flush text... */ httpFlush(http); /* * Grab new location from HTTP data... */ httpSeparate(httpGetField(http, HTTP_FIELD_LOCATION), method, username, hostname, &port, resource); status = HTTP_ERROR; } } if (status != HTTP_OK) { progress_hide(); progress_error("HTTP error %d: %s!", status, httpStatus(status)); httpFlush(http); return (NULL); } if ((fp = file_temp(filename, sizeof(filename))) == NULL) { progress_hide(); progress_error("Unable to create temporary file \"%s\": %s", filename, strerror(errno)); httpFlush(http); return (NULL); } if ((total = atoi(httpGetField(http, HTTP_FIELD_CONTENT_LENGTH))) == 0) total = 8192; count = 0; while ((bytes = httpRead(http, resource, sizeof(resource))) > 0) { count += bytes; progress_update((100 * count / total) % 101); fwrite(resource, 1, bytes, fp); } progress_hide(); fclose(fp); web_cache[web_files - 1].name = strdup(filename); web_cache[web_files - 1].url = strdup(s); return (filename); } return (NULL); }
http_status_t /* O - HTTP status */ cupsGetFd(http_t *http, /* I - HTTP connection to server */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { int bytes; /* Number of bytes read */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ char if_modified_since[HTTP_MAX_VALUE]; /* If-Modified-Since header */ /* * Range check input... */ DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)\n", http, resource, fd)); if (!http || !resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_ERROR); } /* * Then send GET requests to the HTTP server... */ strlcpy(if_modified_since, httpGetField(http, HTTP_FIELD_IF_MODIFIED_SINCE), sizeof(if_modified_since)); do { httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since); if (httpGet(http, resource)) { if (httpReconnect(http)) { status = HTTP_ERROR; break; } else { status = HTTP_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_CONTINUE); if (status == HTTP_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) break; if (httpReconnect(http)) { status = HTTP_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect(http)) { status = HTTP_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPT_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); /* * See if we actually got the file or an error... */ if (status == HTTP_OK) { /* * Yes, copy the file... */ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) write(fd, buffer, bytes); } else { _cupsSetHTTPError(status); httpFlush(http); } /* * Return the request status... */ return (status); }
http_status_t /* O - HTTP status */ cupsPutFd(http_t *http, /* I - HTTP connection to server */ const char *resource, /* I - Resource name */ int fd) /* I - File descriptor */ { int bytes, /* Number of bytes read */ retries; /* Number of retries */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ /* * Range check input... */ DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)\n", http, resource, fd)); if (!http || !resource || fd < 0) { if (http) http->error = EINVAL; return (HTTP_ERROR); } /* * Then send PUT requests to the HTTP server... */ retries = 0; do { DEBUG_printf(("cupsPutFd: starting attempt, authstring=\"%s\"...\n", http->authstring)); httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetExpect(http, HTTP_CONTINUE); if (httpPut(http, resource)) { if (httpReconnect(http)) { status = HTTP_ERROR; break; } else { status = HTTP_UNAUTHORIZED; continue; } } /* * Wait up to 1 second for a 100-continue response... */ if (httpWait(http, 1000)) status = httpUpdate(http); else status = HTTP_CONTINUE; if (status == HTTP_CONTINUE) { /* * Copy the file... */ lseek(fd, 0, SEEK_SET); while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) if (httpCheck(http)) { if ((status = httpUpdate(http)) != HTTP_CONTINUE) break; } else httpWrite2(http, buffer, bytes); } if (status == HTTP_CONTINUE) { httpWrite2(http, buffer, 0); while ((status = httpUpdate(http)) == HTTP_CONTINUE); } if (status == HTTP_ERROR && !retries) { DEBUG_printf(("cupsPutFd: retry on status %d\n", status)); retries ++; /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect(http)) { status = HTTP_ERROR; break; } /* Try again... */ continue; } DEBUG_printf(("cupsPutFd: status=%d\n", status)); if (status == HTTP_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "PUT", resource)) break; if (httpReconnect(http)) { status = HTTP_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect(http)) { status = HTTP_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPT_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED || (status == HTTP_ERROR && retries < 2)); /* * See if we actually put the file or an error... */ if (status != HTTP_CREATED) { _cupsSetHTTPError(status); httpFlush(http); } return (status); }
http_status_t /* O - @code HTTP_STATUS_CONTINUE@ if OK or HTTP status on error */ cupsWriteRequestData( http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */ const char *buffer, /* I - Bytes to write */ size_t length) /* I - Number of bytes to write */ { int wused; /* Previous bytes in buffer */ /* * Get the default connection as needed... */ DEBUG_printf(("cupsWriteRequestData(http=%p, buffer=%p, " "length=" CUPS_LLFMT ")", http, buffer, CUPS_LLCAST length)); if (!http) { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ if ((http = cg->http) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No active connection"), 1); DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_ERROR."); return (HTTP_STATUS_ERROR); } } /* * Then write to the HTTP connection... */ wused = http->wused; if (httpWrite2(http, buffer, length) < 0) { DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_ERROR."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(http->error), 0); return (HTTP_STATUS_ERROR); } /* * Finally, check if we have any pending data from the server... */ if (length >= HTTP_MAX_BUFFER || http->wused < wused || (wused > 0 && http->wused == length)) { /* * We've written something to the server, so check for response data... */ if (_httpWait(http, 0, 1)) { http_status_t status; /* Status from _httpUpdate */ _httpUpdate(http, &status); if (status >= HTTP_STATUS_MULTIPLE_CHOICES) { _cupsSetHTTPError(status); do { status = httpUpdate(http); } while (status != HTTP_STATUS_ERROR && http->state == HTTP_STATE_POST_RECV); httpFlush(http); } DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status)); return (status); } } DEBUG_puts("1cupsWriteRequestData: Returning HTTP_STATUS_CONTINUE."); return (HTTP_STATUS_CONTINUE); }
static void _post_check (GtkCupsRequest *request) { http_status_t http_status; http_status = request->last_status; GTK_NOTE (PRINTING, g_print ("CUPS Backend: %s - status %i\n", G_STRFUNC, http_status)); request->poll_state = GTK_CUPS_HTTP_READ; if (http_status == HTTP_CONTINUE) { goto again; } else if (http_status == HTTP_UNAUTHORIZED) { int auth_result = -1; httpFlush (request->http); if (request->password_state == GTK_CUPS_PASSWORD_APPLIED) { request->poll_state = GTK_CUPS_HTTP_IDLE; request->password_state = GTK_CUPS_PASSWORD_NOT_VALID; request->state = GTK_CUPS_POST_AUTH; request->need_password = TRUE; return; } /* Negotiate */ if (strncmp (httpGetField (request->http, HTTP_FIELD_WWW_AUTHENTICATE), "Negotiate", 9) == 0) { auth_result = cupsDoAuthentication (request->http, "POST", request->resource); } /* Basic, BasicDigest, Digest and PeerCred */ else { if (request->password_state == GTK_CUPS_PASSWORD_NONE) { cups_username = request->username; cupsSetPasswordCB (passwordCB); /* This call success for PeerCred authentication */ auth_result = cupsDoAuthentication (request->http, "POST", request->resource); if (auth_result != 0) { /* move to AUTH state to let the backend * ask for a password */ request->poll_state = GTK_CUPS_HTTP_IDLE; request->state = GTK_CUPS_POST_AUTH; request->need_password = TRUE; return; } } else { cups_password = request->password; cups_username = request->username; auth_result = cupsDoAuthentication (request->http, "POST", request->resource); if (cups_password != NULL) return; if (request->password != NULL) { memset (request->password, 0, strlen (request->password)); g_free (request->password); request->password = NULL; } request->password_state = GTK_CUPS_PASSWORD_APPLIED; } } if (auth_result || httpReconnect (request->http)) { /* if the password has been used, reset password_state * so that we ask for a new one next time around */ if (cups_password == NULL) request->password_state = GTK_CUPS_PASSWORD_NONE; request->state = GTK_CUPS_POST_DONE; request->poll_state = GTK_CUPS_HTTP_IDLE; gtk_cups_result_set_error (request->result, GTK_CUPS_ERROR_AUTH, 0, 0, "Not authorized"); return; } if (request->data_io != NULL) g_io_channel_seek_position (request->data_io, 0, G_SEEK_SET, NULL); request->state = GTK_CUPS_POST_CONNECT; request->poll_state = GTK_CUPS_HTTP_WRITE; } else if (http_status == HTTP_ERROR) { int error = httpError (request->http); #ifdef G_OS_WIN32 if (error != WSAENETDOWN && error != WSAENETUNREACH) #else if (error != ENETDOWN && error != ENETUNREACH) #endif /* G_OS_WIN32 */ { request->attempts++; goto again; } else { request->state = GTK_CUPS_POST_DONE; request->poll_state = GTK_CUPS_HTTP_IDLE; gtk_cups_result_set_error (request->result, GTK_CUPS_ERROR_HTTP, http_status, error, "Unknown HTTP error"); return; } } else if (http_status == HTTP_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush (request->http); cupsSetEncryption (HTTP_ENCRYPT_REQUIRED); request->state = GTK_CUPS_POST_CONNECT; /* Reconnect... */ httpReconnect (request->http); /* Upgrade with encryption... */ httpEncryption (request->http, HTTP_ENCRYPT_REQUIRED); request->attempts++; goto again; } else if (http_status != HTTP_OK) { int http_errno; http_errno = httpError (request->http); if (http_errno == EPIPE) request->state = GTK_CUPS_POST_CONNECT; else { request->state = GTK_CUPS_POST_DONE; gtk_cups_result_set_error (request->result, GTK_CUPS_ERROR_HTTP, http_status, http_errno, "HTTP Error in POST %s", g_strerror (http_errno)); request->poll_state = GTK_CUPS_HTTP_IDLE; httpFlush (request->http); return; } request->poll_state = GTK_CUPS_HTTP_IDLE; request->last_status = HTTP_CONTINUE; httpFlush (request->http); if (request->own_http) httpClose (request->http); request->http = NULL; return; } else { request->state = GTK_CUPS_POST_READ_RESPONSE; return; } again: http_status = HTTP_CONTINUE; if (httpCheck (request->http)) http_status = httpUpdate (request->http); request->last_status = http_status; }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i, j, k; /* Looping vars */ http_t *http; /* HTTP connection */ http_encryption_t encryption; /* Encryption type */ http_status_t status; /* Status of GET command */ int failures; /* Number of test failures */ char buffer[8192]; /* Input buffer */ long bytes; /* Number of bytes read */ FILE *out; /* Output file */ char encode[256], /* Base64-encoded string */ decode[256]; /* Base64-decoded string */ int decodelen; /* Length of decoded string */ char scheme[HTTP_MAX_URI], /* Scheme from URI */ hostname[HTTP_MAX_URI], /* Hostname from URI */ username[HTTP_MAX_URI], /* Username:password from URI */ resource[HTTP_MAX_URI]; /* Resource from URI */ int port; /* Port number from URI */ http_uri_status_t uri_status; /* Status of URI separation */ http_addrlist_t *addrlist, /* Address list */ *addr; /* Current address */ off_t length, total; /* Length and total bytes */ time_t start, current; /* Start and end time */ const char *encoding; /* Negotiated Content-Encoding */ static const char * const uri_status_strings[] = { "HTTP_URI_STATUS_OVERFLOW", "HTTP_URI_STATUS_BAD_ARGUMENTS", "HTTP_URI_STATUS_BAD_RESOURCE", "HTTP_URI_STATUS_BAD_PORT", "HTTP_URI_STATUS_BAD_HOSTNAME", "HTTP_URI_STATUS_BAD_USERNAME", "HTTP_URI_STATUS_BAD_SCHEME", "HTTP_URI_STATUS_BAD_URI", "HTTP_URI_STATUS_OK", "HTTP_URI_STATUS_MISSING_SCHEME", "HTTP_URI_STATUS_UNKNOWN_SCHEME", "HTTP_URI_STATUS_MISSING_RESOURCE" }; /* * Do API tests if we don't have a URL on the command-line... */ if (argc == 1) { failures = 0; /* * httpGetDateString()/httpGetDateTime() */ fputs("httpGetDateString()/httpGetDateTime(): ", stdout); start = time(NULL); strlcpy(buffer, httpGetDateString(start), sizeof(buffer)); current = httpGetDateTime(buffer); i = (int)(current - start); if (i < 0) i = -i; if (!i) puts("PASS"); else { failures ++; puts("FAIL"); printf(" Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600, (i / 60) % 60, i % 60); printf(" httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer); printf(" httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current); printf(" httpGetDateString(%d) returned \"%s\"\n", (int)current, httpGetDateString(current)); } /* * httpDecode64_2()/httpEncode64_2() */ fputs("httpDecode64_2()/httpEncode64_2(): ", stdout); for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++) { httpEncode64_2(encode, sizeof(encode), base64_tests[i][0], (int)strlen(base64_tests[i][0])); decodelen = (int)sizeof(decode); httpDecode64_2(decode, &decodelen, base64_tests[i][1]); if (strcmp(decode, base64_tests[i][0])) { failures ++; if (j) { puts("FAIL"); j = 1; } printf(" httpDecode64_2() returned \"%s\", expected \"%s\"...\n", decode, base64_tests[i][0]); } if (strcmp(encode, base64_tests[i][1])) { failures ++; if (j) { puts("FAIL"); j = 1; } printf(" httpEncode64_2() returned \"%s\", expected \"%s\"...\n", encode, base64_tests[i][1]); } } if (!j) puts("PASS"); /* * httpGetHostname() */ fputs("httpGetHostname(): ", stdout); if (httpGetHostname(NULL, hostname, sizeof(hostname))) printf("PASS (%s)\n", hostname); else { failures ++; puts("FAIL"); } /* * httpAddrGetList() */ printf("httpAddrGetList(%s): ", hostname); addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL); if (addrlist) { for (i = 0, addr = addrlist; addr; i ++, addr = addr->next) { char numeric[1024]; /* Numeric IP address */ httpAddrString(&(addr->addr), numeric, sizeof(numeric)); if (!strcmp(numeric, "UNKNOWN")) break; } if (addr) printf("FAIL (bad address for %s)\n", hostname); else printf("PASS (%d address(es) for %s)\n", i, hostname); httpAddrFreeList(addrlist); } else if (isdigit(hostname[0] & 255)) { puts("FAIL (ignored because hostname is numeric)"); } else { failures ++; puts("FAIL"); } /* * Test httpSeparateURI()... */ fputs("httpSeparateURI(): ", stdout); for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) { uri_status = httpSeparateURI(HTTP_URI_CODING_MOST, uri_tests[i].uri, scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (uri_status != uri_tests[i].result || strcmp(scheme, uri_tests[i].scheme) || strcmp(username, uri_tests[i].username) || strcmp(hostname, uri_tests[i].hostname) || port != uri_tests[i].port || strcmp(resource, uri_tests[i].resource)) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\":\n", uri_tests[i].uri); if (uri_status != uri_tests[i].result) printf(" Returned %s instead of %s\n", uri_status_strings[uri_status + 8], uri_status_strings[uri_tests[i].result + 8]); if (strcmp(scheme, uri_tests[i].scheme)) printf(" Scheme \"%s\" instead of \"%s\"\n", scheme, uri_tests[i].scheme); if (strcmp(username, uri_tests[i].username)) printf(" Username \"%s\" instead of \"%s\"\n", username, uri_tests[i].username); if (strcmp(hostname, uri_tests[i].hostname)) printf(" Hostname \"%s\" instead of \"%s\"\n", hostname, uri_tests[i].hostname); if (port != uri_tests[i].port) printf(" Port %d instead of %d\n", port, uri_tests[i].port); if (strcmp(resource, uri_tests[i].resource)) printf(" Resource \"%s\" instead of \"%s\"\n", resource, uri_tests[i].resource); } } if (!j) printf("PASS (%d URIs tested)\n", (int)(sizeof(uri_tests) / sizeof(uri_tests[0]))); /* * Test httpAssembleURI()... */ fputs("httpAssembleURI(): ", stdout); for (i = 0, j = 0, k = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) if (uri_tests[i].result == HTTP_URI_STATUS_OK && !strstr(uri_tests[i].uri, "%64") && strstr(uri_tests[i].uri, "//")) { k ++; uri_status = httpAssembleURI(uri_tests[i].assemble_coding, buffer, sizeof(buffer), uri_tests[i].scheme, uri_tests[i].username, uri_tests[i].hostname, uri_tests[i].assemble_port, uri_tests[i].resource); if (uri_status != HTTP_URI_STATUS_OK) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\": %s\n", uri_tests[i].uri, uri_status_strings[uri_status + 8]); } else if (strcmp(buffer, uri_tests[i].uri)) { failures ++; if (!j) { puts("FAIL"); j = 1; } printf(" \"%s\": assembled = \"%s\"\n", uri_tests[i].uri, buffer); } } if (!j) printf("PASS (%d URIs tested)\n", k); /* * httpAssembleUUID */ fputs("httpAssembleUUID: ", stdout); httpAssembleUUID("hostname.example.com", 631, "printer", 12345, buffer, sizeof(buffer)); if (strncmp(buffer, "urn:uuid:", 9)) { printf("FAIL (%s)\n", buffer); failures ++; } else printf("PASS (%s)\n", buffer); /* * Show a summary and return... */ if (failures) printf("\n%d TESTS FAILED!\n", failures); else puts("\nALL TESTS PASSED!"); return (failures); } else if (strstr(argv[1], "._tcp")) { /* * Test resolving an mDNS name. */ char resolved[1024]; /* Resolved URI */ printf("_httpResolveURI(%s, _HTTP_RESOLVE_DEFAULT): ", argv[1]); fflush(stdout); if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) { puts("FAIL"); return (1); } else printf("PASS (%s)\n", resolved); printf("_httpResolveURI(%s, _HTTP_RESOLVE_FQDN): ", argv[1]); fflush(stdout); if (!_httpResolveURI(argv[1], resolved, sizeof(resolved), _HTTP_RESOLVE_FQDN, NULL, NULL)) { puts("FAIL"); return (1); } else if (strstr(resolved, ".local:")) { printf("FAIL (%s)\n", resolved); return (1); } else { printf("PASS (%s)\n", resolved); return (0); } } else if (!strcmp(argv[1], "-u") && argc == 3) { /* * Test URI separation... */ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, argv[2], scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); printf("uri_status = %s\n", uri_status_strings[uri_status + 8]); printf("scheme = \"%s\"\n", scheme); printf("username = \"%s\"\n", username); printf("hostname = \"%s\"\n", hostname); printf("port = %d\n", port); printf("resource = \"%s\"\n", resource); return (0); } /* * Test HTTP GET requests... */ http = NULL; out = stdout; for (i = 1; i < argc; i ++) { if (!strcmp(argv[i], "-o")) { i ++; if (i >= argc) break; out = fopen(argv[i], "wb"); continue; } httpSeparateURI(HTTP_URI_CODING_MOST, argv[i], scheme, sizeof(scheme), username, sizeof(username), hostname, sizeof(hostname), &port, resource, sizeof(resource)); if (!_cups_strcasecmp(scheme, "https") || !_cups_strcasecmp(scheme, "ipps") || port == 443) encryption = HTTP_ENCRYPTION_ALWAYS; else encryption = HTTP_ENCRYPTION_IF_REQUESTED; http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL); if (http == NULL) { perror(hostname); continue; } printf("Checking file \"%s\"...\n", resource); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); if (httpHead(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); if (status == HTTP_STATUS_OK) puts("HEAD OK:"); else printf("HEAD failed with status %d...\n", status); encoding = httpGetContentEncoding(http); printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, encoding ? encoding : "identity"); do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) { httpClearFields(http); if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } } httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, encoding); if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } else { status = HTTP_STATUS_UNAUTHORIZED; continue; } } while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) { /* * Flush any error message... */ httpFlush(http); /* * See if we can do authentication... */ if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; } if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } continue; } #ifdef HAVE_SSL else if (status == HTTP_STATUS_UPGRADE_REQUIRED) { /* Flush any error message... */ httpFlush(http); /* Reconnect... */ if (httpReconnect2(http, 30000, NULL)) { status = HTTP_STATUS_ERROR; break; } /* Upgrade with encryption... */ httpEncryption(http, HTTP_ENCRYPTION_REQUIRED); /* Try again, this time with encryption enabled... */ continue; } #endif /* HAVE_SSL */ } while (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_UPGRADE_REQUIRED); if (status == HTTP_STATUS_OK) puts("GET OK:"); else printf("GET failed with status %d...\n", status); start = time(NULL); length = httpGetLength2(http); total = 0; while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) { total += bytes; fwrite(buffer, bytes, 1, out); if (out != stdout) { current = time(NULL); if (current == start) current ++; printf("\r" CUPS_LLFMT "/" CUPS_LLFMT " bytes (" CUPS_LLFMT " bytes/sec) ", CUPS_LLCAST total, CUPS_LLCAST length, CUPS_LLCAST (total / (current - start))); fflush(stdout); } } } puts("Closing connection to server..."); httpClose(http); if (out != stdout) fclose(out); return (0); }