ipp_t * /* O - Response data */ cupsDoFileRequest(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 */ const char *filename) /* I - File to send or @code NULL@ for none */ { ipp_t *response; /* IPP response data */ int infile; /* Input file */ DEBUG_printf(("cupsDoFileRequest(http=%p, request=%p(%s), resource=\"%s\", " "filename=\"%s\")", http, request, request ? ippOpString(request->request.op.operation_id) : "?", resource, filename)); if (filename) { if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0) { /* * Can't get file information! */ _cupsSetError(errno == ENOENT ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, NULL, 0); ippDelete(request); return (NULL); } } else infile = -1; response = cupsDoIORequest(http, request, resource, infile, -1); if (infile >= 0) close(infile); return (response); }
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 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); }
cups_array_t * /* O - Array or NULL for no restrictions */ cupsdGetPrivateAttrs( cupsd_policy_t *policy, /* I - Policy */ cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *printer, /* I - Printer, if any */ const char *owner) /* I - Owner of object */ { char *name; /* Current name in access list */ cups_array_t *access_ptr, /* Access array */ *attrs_ptr; /* Attributes array */ const char *username; /* Username associated with request */ ipp_attribute_t *attr; /* Attribute from request */ struct passwd *pw; /* User info */ #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), " "printer=%p(%s), owner=\"%s\")", policy, policy->name, con, con->http.fd, printer, printer ? printer->name : "", owner); #endif /* DEBUG */ /* * Get the access and attributes lists that correspond to the request... */ #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s", ippOpString(con->request->request.op.operation_id)); #endif /* DEBUG */ switch (con->request->request.op.operation_id) { case IPP_GET_SUBSCRIPTIONS : case IPP_GET_SUBSCRIPTION_ATTRIBUTES : case IPP_GET_NOTIFICATIONS : access_ptr = policy->sub_access; attrs_ptr = policy->sub_attrs; break; default : access_ptr = policy->job_access; attrs_ptr = policy->job_attrs; break; } /* * If none of the attributes are private, return NULL now... */ if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL && !_cups_strcasecmp(name, "none")) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); #endif /* DEBUG */ return (NULL); } /* * Otherwise check the user against the access list... */ if (con->username[0]) username = con->username; else if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) username = attr->values[0].string.text; else username = "******"; if (username[0]) { pw = getpwnam(username); endpwent(); } else pw = NULL; #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"", username); #endif /* DEBUG */ /* * Otherwise check the user against the access list... */ for (name = (char *)cupsArrayFirst(access_ptr); name; name = (char *)cupsArrayNext(access_ptr)) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name); #endif /* DEBUG */ if (printer && !_cups_strcasecmp(name, "@ACL")) { char *acl; /* Current ACL user/group */ for (acl = (char *)cupsArrayFirst(printer->users); acl; acl = (char *)cupsArrayNext(printer->users)) { if (acl[0] == '@') { /* * Check group membership... */ if (cupsdCheckGroup(username, pw, acl + 1)) break; } else if (acl[0] == '#') { /* * Check UUID... */ if (cupsdCheckGroup(username, pw, acl)) break; } else if (!_cups_strcasecmp(username, acl)) break; } } else if (owner && !_cups_strcasecmp(name, "@OWNER") && !_cups_strcasecmp(username, owner)) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); #endif /* DEBUG */ return (NULL); } else if (!_cups_strcasecmp(name, "@SYSTEM")) { int i; /* Looping var */ for (i = 0; i < NumSystemGroups; i ++) if (cupsdCheckGroup(username, pw, SystemGroups[i])) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); #endif /* DEBUG */ return (NULL); } } else if (name[0] == '@') { if (cupsdCheckGroup(username, pw, name + 1)) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); #endif /* DEBUG */ return (NULL); } } else if (!_cups_strcasecmp(username, name)) { #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL."); #endif /* DEBUG */ return (NULL); } } /* * No direct access, so return private attributes list... */ #ifdef DEBUG cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list."); #endif /* DEBUG */ return (attrs_ptr); }
size_t /* O - Number of bytes less nul */ _ippAttrString(ipp_attribute_t *attr, /* I - Attribute */ char *buffer, /* I - String buffer or NULL */ size_t bufsize) /* I - Size of string buffer */ { int i; /* Looping var */ char *bufptr, /* Pointer into buffer */ *bufend, /* End of buffer */ temp[256]; /* Temporary string */ const char *ptr; /* Pointer into string */ ipp_value_t *val; /* Current value */ if (!attr || !attr->name) { if (buffer) *buffer = '\0'; return (0); } bufptr = buffer; if (buffer) bufend = buffer + bufsize - 1; else bufend = NULL; for (i = attr->num_values, val = attr->values; i > 0; i --, val ++) { if (val > attr->values) { if (buffer && bufptr < bufend) *bufptr++ = ','; else bufptr ++; } switch (attr->value_tag & ~IPP_TAG_COPY) { case IPP_TAG_ENUM : if (!strcmp(attr->name, "printer-state") && val->integer >= IPP_PRINTER_IDLE && val->integer <= IPP_PRINTER_STOPPED) { ptr = printer_states[val->integer - IPP_PRINTER_IDLE]; if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } else if (!strcmp(attr->name, "job-state") && val->integer >= IPP_JOB_PENDING && val->integer <= IPP_JOB_COMPLETED) { ptr = job_states[val->integer - IPP_JOB_PENDING]; if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } else if (!strcmp(attr->name, "operations-supported")) { ptr = ippOpString(val->integer); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } case IPP_TAG_INTEGER : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d", val->integer); else bufptr += snprintf(temp, sizeof(temp), "%d", val->integer); break; case IPP_TAG_BOOLEAN : if (buffer && bufptr < bufend) strlcpy(bufptr, val->boolean ? "true" : "false", bufend - bufptr + 1); bufptr += val->boolean ? 4 : 5; break; case IPP_TAG_RANGE : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%d-%d", val->range.lower, val->range.upper); else bufptr += snprintf(temp, sizeof(temp), "%d-%d", val->range.lower, val->range.upper); break; case IPP_TAG_RESOLUTION : if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); else bufptr += snprintf(temp, sizeof(temp), "%dx%d%s", val->resolution.xres, val->resolution.yres, val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); break; case IPP_TAG_DATE : { unsigned year; /* Year */ year = (val->date[0] << 8) + val->date[1]; if (val->date[9] == 0 && val->date[10] == 0) snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6]); else snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, val->date[2], val->date[3], val->date[4], val->date[5], val->date[6], val->date[8], val->date[9], val->date[10]); if (buffer && bufptr < bufend) strlcpy(bufptr, temp, bufend - bufptr + 1); bufptr += strlen(temp); } break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_MIMETYPE : case IPP_TAG_LANGUAGE : case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : if (!val->string.text) break; for (ptr = val->string.text; *ptr; ptr ++) { if (*ptr == '\\' || *ptr == '\"') { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; } if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } break; case IPP_TAG_BEGIN_COLLECTION : if (buffer && bufptr < bufend) bufptr += ipp_col_string(val->collection, bufptr, bufend - bufptr + 1); else bufptr += ipp_col_string(val->collection, NULL, 0); break; case IPP_TAG_STRING : for (ptr = val->string.text; *ptr; ptr ++) { if (*ptr == '\\' || _cups_isspace(*ptr)) { if (buffer && bufptr < bufend) *bufptr = '\\'; bufptr ++; if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } else if (!isprint(*ptr & 255)) { if (buffer && bufptr < bufend) bufptr += snprintf(bufptr, bufend - bufptr + 1, "\\%03o", *ptr & 255); else bufptr += snprintf(temp, sizeof(temp), "\\%03o", *ptr & 255); } else { if (buffer && bufptr < bufend) *bufptr = *ptr; bufptr ++; } } break; default : ptr = ippTagString(attr->value_tag); if (buffer && bufptr < bufend) strlcpy(bufptr, ptr, bufend - bufptr + 1); bufptr += strlen(ptr); break; } } if (buffer && bufptr < bufend) *bufptr = '\0'; else if (bufend) *bufend = '\0'; return (bufptr - buffer); }
static int /* O - Exit status */ do_test(const char *server, /* I - Server to use */ int port, /* I - Port number to use */ http_encryption_t encryption, /* I - Encryption to use */ int requests, /* I - Number of requests to send */ const char *opstring, /* I - Operation string */ int verbose) /* I - Verbose output? */ { int i; /* Looping var */ http_t *http; /* Connection to server */ ipp_t *request; /* IPP Request */ struct timeval start, /* Start time */ end; /* End time */ double reqtime, /* Time for this request */ elapsed; /* Elapsed time */ int op; /* Current operation */ static ipp_op_t ops[5] = /* Operations to test... */ { IPP_PRINT_JOB, CUPS_GET_DEFAULT, CUPS_GET_PRINTERS, CUPS_GET_CLASSES, IPP_GET_JOBS }; /* * Connect to the server... */ if ((http = httpConnectEncrypt(server, port, encryption)) == NULL) { printf("testspeed(%d): unable to connect to server - %s\n", (int)getpid(), strerror(errno)); return (1); } /* * Do multiple requests... */ for (elapsed = 0.0, i = 0; i < requests; i ++) { /* * Build a request which requires the following attributes: * * attributes-charset * attributes-natural-language * * In addition, IPP_GET_JOBS needs a printer-uri attribute. */ if (opstring) op = ippOpValue(opstring); else op = ops[i % (int)(sizeof(ops) / sizeof(ops[0]))]; request = ippNewRequest(op); gettimeofday(&start, NULL); if (verbose) printf("testspeed(%d): %.6f %s ", (int)getpid(), elapsed, ippOpString(op)); switch (op) { case IPP_GET_JOBS : ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/"); default : ippDelete(cupsDoRequest(http, request, "/")); break; case IPP_PRINT_JOB : ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/test"); ippDelete(cupsDoFileRequest(http, request, "/printers/test", "../data/testprint.ps")); break; } gettimeofday(&end, NULL); reqtime = (end.tv_sec - start.tv_sec) + 0.000001 * (end.tv_usec - start.tv_usec); elapsed += reqtime; switch (cupsLastError()) { case IPP_OK : case IPP_NOT_FOUND : if (verbose) { printf("succeeded: %s (%.6f)\n", cupsLastErrorString(), reqtime); fflush(stdout); } break; default : if (!verbose) printf("testspeed(%d): %s ", (int)getpid(), ippOpString(ops[i & 3])); printf("failed: %s\n", cupsLastErrorString()); httpClose(http); return (1); } } httpClose(http); printf("testspeed(%d): %d requests in %.1fs (%.3fs/r, %.1fr/s)\n", (int)getpid(), i, elapsed, elapsed / i, i / elapsed); return (0); }
void cupsEncodeOptions2( ipp_t *ipp, /* I - Request to add to */ int num_options, /* I - Number of options */ cups_option_t *options, /* I - Options */ ipp_tag_t group_tag) /* I - Group to encode */ { int i, j; /* Looping vars */ int count; /* Number of values */ char *s, /* Pointer into option value */ *val, /* Pointer to option value */ *copy, /* Copy of option value */ *sep, /* Option separator */ quote; /* Quote character */ ipp_attribute_t *attr; /* IPP attribute */ ipp_tag_t value_tag; /* IPP value tag */ cups_option_t *option; /* Current option */ ipp_t *collection; /* Collection value */ int num_cols; /* Number of collection values */ cups_option_t *cols; /* Collection values */ ipp_op_t op; /* Operation for this request */ const ipp_op_t *ops; /* List of allowed operations */ DEBUG_printf(("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, " "group_tag=%x)", ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, options, group_tag)); /* * Range check input... */ if (!ipp || num_options < 1 || !options) return; /* * Do special handling for the document-format/raw options... */ op = ippGetOperation(ipp); if (group_tag == IPP_TAG_OPERATION && (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI || op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI)) { /* * Handle the document format stuff first... */ if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, val); else if (cupsGetOption("raw", num_options, options)) ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/vnd.cups-raw"); else ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "application/octet-stream"); } /* * Then loop through the options... */ for (i = num_options, option = options; i > 0; i --, option ++) { _ipp_option_t *match; /* Matching attribute */ /* * Skip document format options that are handled above... */ if (!_cups_strcasecmp(option->name, "raw") || !_cups_strcasecmp(option->name, "document-format") || !option->name[0]) continue; /* * Figure out the proper value and group tags for this option... */ if ((match = _ippFindOption(option->name)) != NULL) { if (match->group_tag != group_tag && match->alt_group_tag != group_tag) continue; value_tag = match->value_tag; if (match->operations) ops = match->operations; else if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else if (group_tag == IPP_TAG_SUBSCRIPTION) ops = ipp_sub_creation; else if (group_tag == IPP_TAG_PRINTER) ops = ipp_set_printer; else { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else { int namelen; /* Length of name */ namelen = (int)strlen(option->name); if (namelen < 10 || (strcmp(option->name + namelen - 8, "-default") && strcmp(option->name + namelen - 10, "-supported"))) { if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } } else if (group_tag != IPP_TAG_PRINTER) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } if (group_tag == IPP_TAG_JOB) ops = ipp_job_creation; else if (group_tag == IPP_TAG_DOCUMENT) ops = ipp_doc_creation; else ops = ipp_set_printer; if (!_cups_strcasecmp(option->value, "true") || !_cups_strcasecmp(option->value, "false")) value_tag = IPP_TAG_BOOLEAN; else value_tag = IPP_TAG_NAME; } /* * Verify that we send this attribute for this operation... */ while (*ops != IPP_OP_CUPS_NONE) if (op == *ops) break; else ops ++; if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE) { DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name)); continue; } /* * Count the number of values... */ if (match && match->multivalue) { for (count = 1, sep = option->value, quote = 0; *sep; sep ++) { if (*sep == quote) quote = 0; else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Skip quoted option value... */ quote = *sep++; } else if (*sep == ',' && !quote) count ++; else if (*sep == '\\' && sep[1]) sep ++; } } else count = 1; DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", count=%d", option->name, count)); /* * Allocate memory for the attribute values... */ if ((attr = ippAddStrings(ipp, group_tag, value_tag, option->name, count, NULL, NULL)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!"); return; } if (count > 1) { /* * Make a copy of the value we can fiddle with... */ if ((copy = strdup(option->value)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!"); ippDeleteAttribute(ipp, attr); return; } val = copy; } else { /* * Since we have a single value, use the value directly... */ val = option->value; copy = NULL; } /* * Scan the value string for values... */ for (j = 0, sep = val; j < count; val = sep, j ++) { /* * Find the end of this value and mark it if needed... */ if (count > 1) { for (quote = 0; *sep; sep ++) { if (*sep == quote) { /* * Finish quoted value... */ quote = 0; } else if (!quote && (*sep == '\'' || *sep == '\"')) { /* * Handle quoted option value... */ quote = *sep; } else if (*sep == ',' && count > 1) break; else if (*sep == '\\' && sep[1]) { /* * Skip quoted character... */ sep ++; } } if (*sep == ',') *sep++ = '\0'; } /* * Copy the option value(s) over as needed by the type... */ switch (attr->value_tag) { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : /* * Integer/enumeration value... */ attr->values[j].integer = (int)strtol(val, &s, 10); DEBUG_printf(("2cupsEncodeOptions2: Added integer option value " "%d...", attr->values[j].integer)); break; case IPP_TAG_BOOLEAN : if (!_cups_strcasecmp(val, "true") || !_cups_strcasecmp(val, "on") || !_cups_strcasecmp(val, "yes")) { /* * Boolean value - true... */ attr->values[j].boolean = 1; DEBUG_puts("2cupsEncodeOptions2: Added boolean true value..."); } else { /* * Boolean value - false... */ attr->values[j].boolean = 0; DEBUG_puts("2cupsEncodeOptions2: Added boolean false value..."); } break; case IPP_TAG_RANGE : /* * Range... */ if (*val == '-') { attr->values[j].range.lower = 1; s = val; } else attr->values[j].range.lower = (int)strtol(val, &s, 10); if (*s == '-') { if (s[1]) attr->values[j].range.upper = (int)strtol(s + 1, NULL, 10); else attr->values[j].range.upper = 2147483647; } else attr->values[j].range.upper = attr->values[j].range.lower; DEBUG_printf(("2cupsEncodeOptions2: Added range option value " "%d-%d...", attr->values[j].range.lower, attr->values[j].range.upper)); break; case IPP_TAG_RESOLUTION : /* * Resolution... */ attr->values[j].resolution.xres = (int)strtol(val, &s, 10); if (*s == 'x') attr->values[j].resolution.yres = (int)strtol(s + 1, &s, 10); else attr->values[j].resolution.yres = attr->values[j].resolution.xres; if (!_cups_strcasecmp(s, "dpc") || !_cups_strcasecmp(s, "dpcm")) attr->values[j].resolution.units = IPP_RES_PER_CM; else attr->values[j].resolution.units = IPP_RES_PER_INCH; DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value " "%s...", val)); break; case IPP_TAG_STRING : /* * octet-string */ attr->values[j].unknown.length = (int)strlen(val); attr->values[j].unknown.data = strdup(val); DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value " "\"%s\"...", (char *)attr->values[j].unknown.data)); break; case IPP_TAG_BEGIN_COLLECTION : /* * Collection value */ num_cols = cupsParseOptions(val, 0, &cols); if ((collection = ippNew()) == NULL) { cupsFreeOptions(num_cols, cols); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } attr->values[j].collection = collection; cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB); cupsFreeOptions(num_cols, cols); break; default : if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL) { /* * Ran out of memory! */ DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!"); if (copy) free(copy); ippDeleteAttribute(ipp, attr); return; } DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...", val)); break; } } if (copy) free(copy); } }
ipp_t * /* O - Response data */ cupsDoRequest(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 */ { DEBUG_printf(("cupsDoRequest(http=%p, request=%p(%s), resource=\"%s\")", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource)); return (cupsDoIORequest(http, request, resource, -1, -1)); }