libidav/resource.c

changeset 728
35a421f441d5
parent 713
a1c36a6410f6
child 736
40be8db6fe45
equal deleted inserted replaced
727:56e6b5ccbf11 728:35a421f441d5
754 ucx_mempool_destroy(mp); 754 ucx_mempool_destroy(mp);
755 return ret; 755 return ret;
756 } 756 }
757 757
758 758
759 /*
760 * read wrapper with integrated hashing
761 */
762
763 typedef struct {
764 DAV_SHA_CTX *sha;
765 void *stream;
766 dav_read_func read;
767 dav_seek_func seek;
768 int error;
769 } HashStream;
770
771 static void init_hash_stream(HashStream *hstr, void *stream, dav_read_func readfn, dav_seek_func seekfn) { 759 static void init_hash_stream(HashStream *hstr, void *stream, dav_read_func readfn, dav_seek_func seekfn) {
772 hstr->sha = NULL; 760 hstr->sha = NULL;
773 hstr->stream = stream; 761 hstr->stream = stream;
774 hstr->read = readfn; 762 hstr->read = readfn;
775 hstr->seek = seekfn; 763 hstr->seek = seekfn;
1553 ucx_map_free(map); 1541 ucx_map_free(map);
1554 return NULL; 1542 return NULL;
1555 } 1543 }
1556 return map; 1544 return map;
1557 } 1545 }
1546
1547
1548 /* ----------------------------- streams ----------------------------- */
1549
1550 static size_t in_write(const char *ptr, size_t size, size_t nitems, void *in_stream) {
1551 DavInputStream *in = in_stream;
1552 size_t len = size * nitems;
1553
1554 if(in->alloc < len) {
1555 char *newb = realloc(in->buffer, len);
1556 if(!newb) {
1557 if(in->buffer) free(in->buffer);
1558 in->eof = 1;
1559 return 0;
1560 }
1561
1562 in->buffer = newb;
1563 in->alloc = len;
1564 }
1565
1566 memcpy(in->buffer, ptr, len);
1567
1568 in->size = len;
1569 in->pos = 0;
1570
1571 return nitems;
1572 }
1573
1574 DavInputStream* dav_inputstream_open(DavResource *res) {
1575 DavSession *sn = res->session;
1576
1577 DavInputStream *in = dav_session_malloc(sn, sizeof(DavInputStream));
1578 if(!in) {
1579 return NULL;
1580 }
1581 memset(in, 0, sizeof(DavInputStream));
1582
1583 in->res = res;
1584
1585 in->c = curl_easy_duphandle(sn->handle);
1586 char *url = util_get_url(sn, dav_resource_get_href(res));
1587 curl_easy_setopt(in->c, CURLOPT_URL, url);
1588 free(url);
1589
1590 in->m = curl_multi_init();
1591
1592 curl_easy_setopt(in->c, CURLOPT_HTTPHEADER, NULL);
1593 curl_easy_setopt(in->c, CURLOPT_CUSTOMREQUEST, NULL);
1594 curl_easy_setopt(in->c, CURLOPT_PUT, 0L);
1595 curl_easy_setopt(in->c, CURLOPT_UPLOAD, 0L);
1596
1597 curl_multi_add_handle(in->m, in->c);
1598
1599 dav_write_func write_fnc = (dav_write_func)in_write;
1600 void *stream = in;
1601
1602 // check encryption
1603 AESDecrypter *dec = NULL;
1604 DavKey *key = NULL;
1605 if(DAV_DECRYPT_CONTENT(sn)) {
1606 char *keyname = dav_get_string_property_ns(res, DAV_NS, "crypto-key");
1607 if(keyname) {
1608 key = dav_context_get_key(sn->context, keyname);
1609 if(key) {
1610 dec = aes_decrypter_new(key, stream, write_fnc);
1611 stream = dec;
1612 write_fnc = (dav_write_func)aes_write;
1613 }
1614 }
1615 }
1616
1617 curl_easy_setopt(in->c, CURLOPT_WRITEFUNCTION, write_fnc);
1618 curl_easy_setopt(in->c, CURLOPT_WRITEDATA, stream);
1619
1620 in->dec = dec;
1621
1622 return in;
1623 }
1624
1625 size_t dav_read(void *buf, size_t size, size_t nitems, DavInputStream *in) {
1626 size_t len = in->size - in->pos;
1627 size_t rl = size * nitems;
1628 if(len > 0) {
1629 len = rl > len ? len : rl;
1630 len -= len % size;
1631 memcpy(buf, in->buffer + in->pos, len);
1632 in->pos += len;
1633 return len / size;
1634 }
1635 in->size = 0;
1636
1637 if(in->eof) {
1638 if(in->dec) {
1639 aes_decrypter_shutdown(in->dec); // get final bytes
1640 aes_decrypter_close(in->dec);
1641 in->dec = NULL;
1642 } else {
1643 return 0;
1644 }
1645 } else {
1646 int running;
1647 while(!in->eof && in->size == 0) {
1648 CURLMcode r = curl_multi_perform(in->m, &running);
1649 if(r != CURLM_OK || running == 0) {
1650 in->eof = 1;
1651 break;
1652 }
1653
1654 int numfds;
1655 if(curl_multi_poll(in->m, NULL, 0, 5000, &numfds) != CURLM_OK) {
1656 in->eof = 1;
1657 }
1658 }
1659 }
1660
1661 return in->size > 0 ? dav_read(buf, size, nitems, in) : 0;
1662 }
1663
1664 void dav_inputstream_close(DavInputStream *in) {
1665 curl_multi_cleanup(in->m);
1666 curl_easy_cleanup(in->c);
1667 if(in->buffer) free(in->buffer);
1668 dav_session_free(in->res->session, in);
1669 }
1670
1671
1672 static size_t out_read(char *ptr, size_t size, size_t nitems, void *out_stream) {
1673 DavOutputStream *out = out_stream;
1674 size_t len = size * nitems;
1675 size_t available = out->size - out->pos;
1676 if(available == 0) {
1677 return 0;
1678 }
1679
1680 size_t r = len > available ? available : len;
1681 r -= r % size;
1682 memcpy(ptr, out->buffer + out->pos, r);
1683
1684 out->pos += r;
1685
1686 return r / size;
1687 }
1688
1689 static size_t dummy_write(void *buf, size_t s, size_t n, void *data) {
1690 return s*n;
1691 }
1692
1693 DavOutputStream* dav_outputstream_open(DavResource *res) {
1694 DavSession *sn = res->session;
1695
1696 DavOutputStream *out = dav_session_malloc(sn, sizeof(DavOutputStream));
1697 if(!out) {
1698 return NULL;
1699 }
1700 memset(out, 0, sizeof(DavOutputStream));
1701
1702 out->res = res;
1703
1704 out->c = curl_easy_duphandle(sn->handle);
1705 char *url = util_get_url(sn, dav_resource_get_href(res));
1706 curl_easy_setopt(out->c, CURLOPT_URL, url);
1707 free(url);
1708
1709 out->m = curl_multi_init();
1710 curl_multi_add_handle(out->m, out->c);
1711
1712 void *stream = out;
1713 dav_read_func read_fnc = (dav_read_func)out_read;
1714
1715 // if encryption or hashing in enabled, we need a stream wrapper
1716 if(DAV_ENCRYPT_CONTENT(sn) && sn->key) {
1717 AESEncrypter *enc = aes_encrypter_new(sn->key, out, (dav_read_func)out_read, NULL);
1718 out->enc = enc;
1719 stream = enc;
1720 read_fnc = (dav_read_func)aes_read;
1721 } else if((sn->flags & DAV_SESSION_STORE_HASH) == DAV_SESSION_STORE_HASH) {
1722 HashStream *hstr = dav_session_malloc(sn, sizeof(HashStream));
1723 out->hstr = hstr;
1724 init_hash_stream(hstr, out, (dav_read_func)out_read, NULL);
1725 stream = hstr;
1726 read_fnc = (dav_read_func)dav_read_h;
1727 }
1728
1729 curl_easy_setopt(out->c, CURLOPT_HEADERFUNCTION, NULL);
1730 curl_easy_setopt(out->c, CURLOPT_HTTPHEADER, NULL);
1731 curl_easy_setopt(out->c, CURLOPT_CUSTOMREQUEST, NULL);
1732 curl_easy_setopt(out->c, CURLOPT_PUT, 1L);
1733 curl_easy_setopt(out->c, CURLOPT_UPLOAD, 1L);
1734 curl_easy_setopt(out->c, CURLOPT_READFUNCTION, read_fnc);
1735 curl_easy_setopt(out->c, CURLOPT_READDATA, stream);
1736 curl_easy_setopt(out->c, CURLOPT_SEEKFUNCTION, NULL);
1737 curl_easy_setopt(out->c, CURLOPT_INFILESIZE, -1);
1738 curl_easy_setopt(out->c, CURLOPT_INFILESIZE_LARGE, -1L);
1739
1740 curl_easy_setopt(out->c, CURLOPT_WRITEFUNCTION, dummy_write);
1741 curl_easy_setopt(out->c, CURLOPT_WRITEDATA, NULL);
1742
1743 return out;
1744 }
1745
1746 size_t dav_write(const void *buf, size_t size, size_t nitems, DavOutputStream *out) {
1747 if(out->eof) return 0;
1748
1749 out->buffer = buf;
1750 out->size = size * nitems;
1751 out->pos = 0;
1752
1753 int running;
1754 while(!out->eof && (out->size == 0 || out->size - out->pos > 0)) {
1755 CURLMcode r = curl_multi_perform(out->m, &running);
1756 if(r != CURLM_OK || running == 0) {
1757 out->eof = 1;
1758 break;
1759 }
1760
1761 int numfds;
1762 if(curl_multi_poll(out->m, NULL, 0, 5000, &numfds) != CURLM_OK) {
1763 out->eof = 1;
1764 }
1765 }
1766
1767 return (out->size - out->pos) / size;
1768 }
1769
1770 int dav_outputstream_close(DavOutputStream *out) {
1771 DavSession *sn = out->res->session;
1772 DavResource *res = out->res;
1773 DavResourceData *data = res->data;
1774
1775 int ret = 0;
1776
1777 dav_write(NULL, 1, 0, out);
1778
1779 curl_multi_cleanup(out->m);
1780 curl_easy_cleanup(out->c);
1781
1782 int store = 0;
1783 if(out->enc) {
1784 // get sha256 hash
1785 char hash[32];
1786 dav_get_hash(&out->enc->sha256, (unsigned char*)data->hash);
1787 aes_encrypter_close(out->enc);
1788 char *enc_hash = aes_encrypt(hash, DAV_SHA256_DIGEST_LENGTH, sn->key);
1789 // add crypto properties
1790 if(resource_add_crypto_info(sn, out->res->href, out->res->name, enc_hash)) {
1791 ret = 1;
1792 }
1793 free(enc_hash);
1794 } else if(out->hstr) {
1795 dav_hash_final(out->hstr->sha, (unsigned char*)data->hash);
1796 char *hash = util_hexstr((unsigned char*)data->hash, 32);
1797 dav_set_string_property_ns(res, DAV_NS, "content-hash", hash);
1798 free(hash);
1799 dav_session_free(sn, out->hstr);
1800 store = 1;
1801 }
1802
1803 if(store) {
1804 ret = dav_store(out->res);
1805 }
1806
1807 dav_session_free(out->res->session, out);
1808
1809 return ret;
1810 }
1811

mercurial