~michihenning/storage-framework/check-server-side-metadata

« back to all changes in this revision

Viewing changes to src/qt/client/internal/remote_client/validate.cpp

  • Committer: Tarmac
  • Author(s): Michi Henning
  • Date: 2016-08-11 06:28:04 UTC
  • mfrom: (10.12.7 marshal-metadata)
  • Revision ID: tarmac-20160811062804-xdb4d33u2fiqcydv
Marshal known metadata, with sanity checks on the client side.

Approved by unity-api-1-bot, James Henstridge.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 Canonical Ltd
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authors: Michi Henning <michi.henning@canonical.com>
 
17
 */
 
18
 
 
19
#include <unity/storage/internal/ItemMetadata.h>
 
20
 
 
21
#include <unity/storage/provider/metadata_keys.h>
 
22
#include <unity/storage/qt/client/Exceptions.h>
 
23
 
 
24
#include <QDateTime>
 
25
#include <QString>
 
26
 
 
27
using namespace unity::storage::internal;
 
28
using namespace std;
 
29
 
 
30
namespace unity
 
31
{
 
32
namespace storage
 
33
{
 
34
namespace qt
 
35
{
 
36
namespace client
 
37
{
 
38
namespace internal
 
39
{
 
40
namespace remote_client
 
41
{
 
42
 
 
43
namespace
 
44
{
 
45
 
 
46
// Check that actual type and value match the expect type and value for a particular metadata entry.
 
47
 
 
48
void validate_type_and_value(QString const& prefix,
 
49
                             QMapIterator<QString, QVariant> actual,
 
50
                             unordered_map<string, provider::MetadataType>::const_iterator known)
 
51
{
 
52
    using namespace unity::storage::provider;
 
53
 
 
54
    switch (known->second)
 
55
    {
 
56
        case MetadataType::iso_8601_date_time:
 
57
        {
 
58
            if (actual.value().type() != QVariant::String)
 
59
            {
 
60
                throw LocalCommsException(prefix + actual.key() + ": expected value of type String, "
 
61
                                          " but received value of type " + actual.value().typeName());
 
62
            }
 
63
            QDateTime dt = QDateTime::fromString(actual.value().toString(), Qt::ISODate);
 
64
            if (!dt.isValid())
 
65
            {
 
66
                throw LocalCommsException(prefix + actual.key() + ": value \"" + actual.value().toString()
 
67
                                          + "\" does not parse as ISO-8601 date");
 
68
            }
 
69
            auto timespec = dt.timeSpec();
 
70
            if (timespec == Qt::LocalTime)
 
71
            {
 
72
                throw LocalCommsException(prefix + actual.key() + ": value \"" + actual.value().toString()
 
73
                                          + "\" lacks a time zone specification");
 
74
            }
 
75
            break;
 
76
        }
 
77
        case MetadataType::int64:
 
78
        {
 
79
            if (actual.value().type() != QVariant::LongLong)
 
80
            {
 
81
                throw LocalCommsException(prefix + actual.key() + ": expected value of type LongLong, "
 
82
                                          " but received value of type " + actual.value().typeName());
 
83
            }
 
84
            break;
 
85
        }
 
86
        default:
 
87
        {
 
88
            abort();  // Impossible.  // LCOV_EXCL_LINE
 
89
        }
 
90
    }
 
91
}
 
92
 
 
93
}
 
94
 
 
95
void validate(QString const& method, ItemMetadata const& md)
 
96
{
 
97
    using namespace unity::storage::provider;
 
98
 
 
99
    QString prefix = method + ": received invalid metadata from server: ";
 
100
 
 
101
    // Basic sanity checks for mandatory fields.
 
102
    if (md.item_id.isEmpty())
 
103
    {
 
104
        throw LocalCommsException(prefix + "item_id cannot be empty");
 
105
    }
 
106
    if (md.parent_id.isEmpty() && md.type != ItemType::root)
 
107
    {
 
108
        throw LocalCommsException(prefix + "parent_id of file or folder cannot be empty");
 
109
    }
 
110
    if (!md.parent_id.isEmpty() && md.type == ItemType::root)
 
111
    {
 
112
        throw LocalCommsException(prefix + "metadata: parent_id of root cannot be non-empty");
 
113
    }
 
114
    if (md.name.isEmpty())
 
115
    {
 
116
        throw LocalCommsException(prefix + "name cannot be empty");
 
117
    }
 
118
    if (md.etag.isEmpty())
 
119
    {
 
120
        throw LocalCommsException(prefix + "etag cannot be empty");
 
121
    }
 
122
 
 
123
    // Sanity check metadata to make sure only known metadata keys appear.
 
124
    QMapIterator<QString, QVariant> actual(md.metadata);
 
125
    while (actual.hasNext())
 
126
    {
 
127
        actual.next();
 
128
        auto known = known_metadata.find(actual.key().toStdString());
 
129
        if (known == known_metadata.end())
 
130
        {
 
131
            throw LocalCommsException(prefix + "unknown metadata key:" + actual.key());
 
132
        }
 
133
        validate_type_and_value(prefix, actual, known);
 
134
    }
 
135
 
 
136
    // Sanity check metadata to make sure that mandatory fields are present.
 
137
    if (md.type == ItemType::file)
 
138
    {
 
139
        if (!md.metadata.contains(SIZE_IN_BYTES))
 
140
        {
 
141
            throw LocalCommsException(prefix + "missing key " + SIZE_IN_BYTES + " in metadata for " + md.item_id);
 
142
        }
 
143
        if (!md.metadata.contains(LAST_MODIFIED_TIME))
 
144
        {
 
145
            throw LocalCommsException(prefix + "missing key " + LAST_MODIFIED_TIME + " in metadata for " + md.item_id);
 
146
        }
 
147
    }
 
148
}
 
149
 
 
150
}  // namespace remote_client
 
151
}  // namespace internal
 
152
}  // namespace client
 
153
}  // namespace qt
 
154
}  // namespace storage
 
155
}  // namespace unity